package com.onlineMIS.ORM.DAO.headQ.finance;

import java.io.ByteArrayInputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.onlineMIS.ORM.DAO.Response;
import com.onlineMIS.ORM.DAO.chainS.user.ChainStoreDaoImpl;
import com.onlineMIS.ORM.DAO.chainS.user.ChainStoreService;
import com.onlineMIS.ORM.DAO.chainS.user.ChainUserInforService;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQEntityTagDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQTagDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQTagGroupDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.custMgmt.HeadQCustDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.inventory.InventoryOrderDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.finance.FinanceBillSupplierDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.finance.FinanceBillSupplierItemDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.finance.FinanceCategoryFlowDaoImpl;
import com.onlineMIS.ORM.entity.base.BaseOrder;
import com.onlineMIS.ORM.entity.base.Pager;
import com.onlineMIS.ORM.entity.chainS.user.ChainRoleType;
import com.onlineMIS.ORM.entity.chainS.user.ChainStore;
import com.onlineMIS.ORM.entity.chainS.user.ChainUserInfor;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTag;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTagGroup;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadqEntityTag;
import com.onlineMIS.ORM.entity.headQ.custMgmt.HeadQCust;
import com.onlineMIS.ORM.entity.headQ.finance.AccountsFlowTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.AllAccountsFlowTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.AllAccountsJSFlowTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlow;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlowDetailsTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlowReportExcleVO;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlowReportItem;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlowTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.ChainFinanceTrace;
import com.onlineMIS.ORM.entity.headQ.finance.ExpenseHq;
import com.onlineMIS.ORM.entity.headQ.finance.ExpenseHqItem;
import com.onlineMIS.ORM.entity.headQ.finance.ExpenseHqItemDetailsTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.ExpenseHqType;
import com.onlineMIS.ORM.entity.headQ.finance.ExpenseHqVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBill;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillCorpFlow;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillCorpFlowVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillCustomerVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillFlowDetailsVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillItem;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillPrintVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillReportTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceCategory;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceCategoryFlow;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceCategoryTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceCategoryVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinancePrestoreInfoVO;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrder;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.CustFinanceSummaryItem;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.FinanceBillSupplier;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.FinanceBillSupplierItem;
import com.onlineMIS.ORM.entity.headQ.user.UserInfor;
import com.onlineMIS.action.headQ.finance.FinanceActionFormBean;
import com.onlineMIS.action.headQ.finance.FinanceActionUIBean;
import com.onlineMIS.common.Common_util;
import com.onlineMIS.common.DateUtils;
import com.onlineMIS.common.ExcelUtil;
import com.onlineMIS.common.StrCheckUtils;
import com.onlineMIS.common.loggerLocal;
import com.onlineMIS.filter.SystemParm;
import com.onlineMIS.sorter.ChainAcctFlowReportItemSort;

@Service
public class FinanceService {
	
	@Autowired
	private FinanceBillCorpFlowImpl financeBillCoreFlowImpl;

	@Autowired
	private FinanceCategoryFlowDaoImpl financeCategoryFlowDaoImpl;
	
	@Autowired
	private FinanceBillImpl financeBillImpl;
	
	@Autowired
	private ChainAcctFlowDaoImpl chainAcctFlowDaoImpl;
	
	@Autowired
	private FinanceCategoryImpl financeCategoryImpl;
	
	@Autowired
	private ChainStoreDaoImpl chainStoreDaoImpl;
	
	@Autowired
	private ChainStoreService chainStoreService;
	
	@Autowired
	private ChainFinanceTraceImpl chainFinanceTraceImpl;
	@Autowired
	private HeadQCustDaoImpl headQCustDaoImpl;
	@Autowired
	private HeadQTagDaoImpl headQTagDaoImpl;
	@Autowired
	private InventoryOrderDAOImpl inventoryOrderDAOImpl;

	@Autowired
	private FinanceCategoryFlowImpl financeCategoryFlowImpl;
	
	@Autowired
	private FinanceBillItemImpl financeBillItemImpl;
	
	@Autowired
	private FinanceBillSupplierDaoImpl financeBillSupplierDaoImpl;
	@Autowired
	private FinanceBillSupplierItemDaoImpl financeBillSupplierItemDaoImpl;
	@Autowired
	private FbSupplierItemDaoImpl fbSupplierItemDaoImpl;
	@Autowired
	private ExpenseHqTypeImpl expenseHqTypeImpl;
	@Autowired
	private ExpenseHqImpl expenseHqImpl;
	@Autowired
	private ExpenseHqItemImpl expenseHqItemImpl;
	@Autowired
	private HeadQEntityTagDaoImpl headQEntityTagDaoImpl;
	@Autowired
	private HeadQTagGroupDaoImpl tagGroupDaoImpl;

	/**
	 * to prepare the bean when create the finance bill
	 * @param formBean
	 * @param uiBean
	 */
	public Response prepareCreateBill(FinanceActionFormBean formBean, FinanceActionUIBean uiBean){
		
		Response response = initializeFianceBill(formBean);
		return response;
	}
	
	/**
	 * 下载 批发财务单据
	 * @param excelPath
	 * @param searchStartTime
	 * @param name
	 * @param searchEndTime
	 * @param status
	 * @param type
	 * @return
	 */
	@Transactional
	public Response generateFinanceBillHQRptExcel(String excelPath, FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			boolean cached = false;
		    DetachedCriteria criteria = buildSearchFHQBills(formBean);
		    criteria.addOrder(Order.desc("billDate"));
		    // 查询所有符合条件的财务单据
		    List<FinanceBill> fianBills =financeBillImpl.getByCritera(criteria, cached);
	
			List<FinanceBillVO> list = new ArrayList<FinanceBillVO>();
			for (FinanceBill financeBill : fianBills) {
				FinanceBillVO financeBillVO = new FinanceBillVO(financeBill);
				list.add(financeBillVO);
			}
			FinanceBillReportTemplate reportTemplate = new FinanceBillReportTemplate(formBean.getSearchStartTime(),
					formBean.getSearchEndTime(), formBean.getHeadQCust().getName(), excelPath, list);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	
	/**
	 * 按条件查询批发财务单据
	 * @param formBean
	 * @return
	 */
	public List<FinanceBill> searchAllFHQBills(FinanceActionFormBean formBean) {
		boolean cached = false;
	    DetachedCriteria criteria = buildSearchFHQBills(formBean);
	    criteria.addOrder(Order.desc("createDate"));
		return financeBillImpl.getByCritera(criteria, cached);
	}
	
	/**
	 * to prepare the bean when edit the finance bill
	 * @param uiBean
	 */
	public void prepareEditBill(FinanceActionFormBean formBean, ChainStore chainStore){
        formBean.setChainStore(chainStore);
	}
	
	/**
	 * initialize the finance bill
	 */
	private Response initializeFianceBill( FinanceActionFormBean formBean){
		Response response = new Response();
		FinanceBill financeBill = formBean.getFinanceBill();
		List<FinanceBillItem> billItems = new ArrayList<FinanceBillItem>();
		// 获取所有财务账户信息
		List<FinanceCategory> allCategories = new ArrayList<FinanceCategory>();
		//客户财务单据-进入初始页面时，默认为收款单
		if (financeBill.getType() == Common_util.ALL_RECORD_NEW) {
			financeBill.setType(FinanceBill.FINANCE_INCOME_HQ);			
		}		
		
		int belongTo2 = 0;
		if (financeBill.getCust() != null) {

			HeadqEntityTag  qxEntityTag = headQEntityTagDaoImpl.selectEntityTag(financeBill.getCust().getId(), HeadQTag.HEADQ_QX_CUST_TAG_ID);
			if (qxEntityTag !=null) {
				belongTo2 = FinanceCategory.BELONG_TO_QX;
			}
			HeadqEntityTag xlcEntityTag = headQEntityTagDaoImpl.selectEntityTag(financeBill.getCust().getId(), HeadQTag.HEADQ_XLC_CUST_TAG_ID);
			if (xlcEntityTag !=null) {
				belongTo2 = FinanceCategory.BELONG_TO_XLC;
			}
			if(qxEntityTag ==null && xlcEntityTag == null) {
				allCategories = null;
				response.setFail("当前客户暂未有归属，请选择客户归属后再创建财务单据");
			}else {
				//1.付款单
				if (financeBill.getType() == FinanceBill.FINANCE_PAID_HQ) {
					allCategories = financeCategoryImpl.selectFcBelongTo(FinanceCategory.BELONG_TO_HQ,belongTo2);
				//2.收款单
				}else if (financeBill.getType() == FinanceBill.FINANCE_INCOME_HQ) {
					allCategories = financeCategoryImpl.selectFcBelongTo(FinanceCategory.BELONG_TO_HQ,belongTo2);			
				//3.应收增加，应收减少	
				}else if (financeBill.getType() == FinanceBill.FINANCE_DECREASE_HQ || financeBill.getType() == FinanceBill.FINANCE_INCREASE_HQ) {
					allCategories.add(financeCategoryImpl.selectByType(FinanceCategory.INCREASE_DECREASE_ACCT_TYPE,belongTo2));
				//4.预存金充值
				}else if (financeBill.getType() == FinanceBill.FINANCE_PREINCOME_HQ) {
					allCategories = financeCategoryImpl.selectFcBelongTo(FinanceCategory.BELONG_TO_HQ,belongTo2);			
				}else if (financeBill.getType() == financeBill.FINANCE_PREINCOME_SPEND_HQ) {
				//5.预存金消费
					allCategories.add(financeCategoryImpl.selectByType(FinanceCategory.PREPAY_ACCT_TYPE,belongTo2));
				}
			}
			//拿到账目信息后，补充客户信息，填充custInput 中客户input输入框的信息
			HeadQCust cust = headQCustDaoImpl.get(financeBill.getCust().getId(), true);
			if (cust != null) {
				formBean.setHeadQCust(cust);
			}
		}
			
		if (allCategories != null){
			for (int i = 0; i < allCategories.size(); i++){
				FinanceBillItem billItem = new FinanceBillItem();
				billItem.setFinanceCategory(allCategories.get(i));
				billItems.add(billItem);
			}
			financeBill.setFinanceBillItemList(billItems);
		}
		financeBill.setBillDate(new java.sql.Date(new Date().getTime()));
		return response;
	}

	/**
	 * save the bill to draft
	 * @param financeBill
	 * @throws ParseException 
	 */
	public Response saveFHQToDraft(FinanceBill financeBill, HeadQCust cust, UserInfor user) throws ParseException {
		Response response = new Response();
		
		financeBill.setCreatorHq(user);
		financeBill.setCust(cust);
		
		if (!validateFinanceHQBill( response,financeBill))
			return response;
		
		ChainStore store = chainStoreDaoImpl.getByClientId(cust.getId());
		if (store != null)
		financeBill.setChainStore(store);
		
		int billId = financeBill.getId();
		FinanceBill originalBill = financeBillImpl.get(billId, true);
		
		if (originalBill == null || originalBill.getStatus() == FinanceBill.STATUS_DRAFT){
			financeBillImpl.evict(originalBill);
			
			financeBill.setStatus(FinanceBill.STATUS_DRAFT);
			
			if (originalBill != null && originalBill.getCreateDate() != null) {
				financeBill.setCreateDate(originalBill.getCreateDate());
				financeBill.setUpdateDate(new Date());
			}else {
				financeBill.setCreateDate(new Date());
				financeBill.setUpdateDate(new Date());
			}
			
			financeBill.putListToSet();
			
			financeBillImpl.saveOrUpdate(financeBill, true);
			
			response.setQuickValue(Response.SUCCESS, "单据成功保存草稿");
		} else {
			response.setReturnCode(Response.ERROR);
			response.setMessage("保存草稿出现错误");
		}
		
		return response;
	}

	
	/**
	 * 单据过账
	 * @param financeBill
	 * @throws ParseException 
	 */
	@Transactional
	public Response postFHQBill(FinanceBill financeBill,UserInfor user, HeadQCust cust) throws ParseException {
		Response response = new Response();		
		
		financeBill.setCreatorHq(user);
		financeBill.setCust(cust);
		
		if (!validateFinanceHQBill( response,financeBill))
			return response;
		
		FinanceBill originalBill = financeBillImpl.get(financeBill.getId(), true);
		
		if (originalBill == null || originalBill.getStatus() == FinanceBill.STATUS_DRAFT){
			financeBillImpl.evict(originalBill);
			// 1.预存金校验
			if (validateFHQBill(financeBill, response) == false)
				return response;
			
			//2.初始化：添加创建时间，单据过账：设置完成状态
			financeBill.setStatus(FinanceBill.STATUS_COMPLETE);
			if (originalBill == null) {
				financeBill.setCreateDate(new Date());
			}
			
			// 如果是草稿，创建时间不变，只修改更新时间
			if (originalBill != null && originalBill.getStatus() == FinanceBill.STATUS_DRAFT) {
				financeBill.setCreateDate(originalBill.getCreateDate());
				financeBill.setUpdateDate(new Date());
			}
			
			
			ChainStore store = chainStoreDaoImpl.getByClientId(financeBill.getCust().getId());
			if (store != null)
			financeBill.setChainStore(store);
			
			financeBill.buildIndex();
			financeBill.putListToSet();
			financeBillImpl.saveOrUpdate(financeBill, true);
			
			//2.0 updat the finance trace
			updateFinanceTrace(financeBill, false);
			
			//3.0 update the acct flow
			updateChainAcctFlow(financeBill, false);
			
			// 4.0 update the finance_category_flow
			financeCategoryFlowDaoImpl.updateFinanceCategoryFlow(null,financeBill,false,false);

			//5.0更新客户表账目
			updateCustAcctBalance(cust);

			response.setReturnCode(Response.SUCCESS);
			response.setMessage("单据成功过账");
		} else {
			response.setReturnCode(Response.ERROR);
			response.setMessage("单据过账出现错误");
		}
		
		return response;
	}
	
	private void updateCustAcctBalance(HeadQCust cust) throws ParseException {
		cust = headQCustDaoImpl.get(cust.getId(), true);
		
		//1. 获取当前客户的账目
		double currentFinance = 0;
		Response response2 = getHeadCustFinance(cust.getId());
		if (response2.isSuccess())
			currentFinance = ((Map<String, Double>)response2.getReturnValue()).get("cf");
		else {
			RuntimeException exception = new RuntimeException("获取客户账目出现问题");
			throw exception;
		}
		
		// 这里更新客户当前欠款金额
		cust.setCurrentAcctBalance(currentFinance);
		headQCustDaoImpl.update(cust, true);
	}

	private void updateFinanceCategoryFlow(FinanceBill bill, boolean isCancel) {
		//int chainId = bill.getChainStore().getChain_id();
				// 修改chainId为custId  
				int custId = bill.getCust().getId();
				int chainId = 0;
				ChainStore chainStore = chainStoreDaoImpl.getByClientId(custId);
				if (chainStore != null)
					chainId = chainStore.getChain_id();
				
				String billId = String.valueOf(bill.getId());
				int offset = isCancel ? -1 : 1;
				billId= isCancel ? "C" + billId : billId;
				
				int billType = bill.getType();
				
				//if it is 总部的付款单需要*-1
				if (billType == FinanceBill.FINANCE_PAID_HQ || billType == FinanceBill.FINANCE_INCREASE_HQ)
					offset *= -1;
				
				double totalAmt = 0;
				//1. to update the bill items
				for (FinanceBillItem billItem : bill.getFinanceBillItemSet()){
					int categoryId = billItem.getFinanceCategory().getId();
					
					double amount = billItem.getTotal();
					
					
				}
		
	}

	/**
	 * to validate the finance bill
	 * @return
	 * @throws ParseException 
	 */
	private boolean validateFinanceHQBill(Response response, FinanceBill bill) throws ParseException{

		HeadQCust headQCust =  bill.getCust();
		if (headQCust == null || headQCust.getId() == 0){
			response.setFail("请选择一个客户再继续");
			return false;
		}
		
		for (FinanceBillItem billItem: bill.getFinanceBillItemList()){
			if (billItem.getTotal() < 0){
				response.setQuickValue(Response.FAIL,"金额必须是大于或等于零的数字");
				return false;
			}   
		}
		//判断流水时间是否超过规定的清账时间之前
		Date accountFlowDate = SystemParm.getAccountFlowDate();
		if (bill.getBillDate().before(accountFlowDate)) {
			response.setQuickValue(Response.FAIL,"无法创建：" + Common_util.dateFormat.format(SystemParm.getAccountFlowDate()) + "之前的单据");
			return false;
		}
		return true;
	}

	/**
	 * 1. 如果是使用预付款的单据,保证不能超过现在存在的预付款
	 * @param financeBill
	 * @param response
	 * @return
	 * @throws ParseException 
	 */
	private boolean validateFHQBill(FinanceBill financeBill, Response response) throws ParseException {
		int custId = financeBill.getCust().getId();
		if (custId == Common_util.ALL_RECORD_NEW){
	    	response.setFail("请选择一个客户再继续操作");
	    	return false;
		}
		HeadQCust cust = headQCustDaoImpl.get(custId, true);
		
		List<FinanceBillItem> items = financeBill.getFinanceBillItemList();
		for (FinanceBillItem item: items){
			int itemType = item.getFinanceCategory().getType();
			double amount = item.getTotal();
			if (itemType == FinanceCategory.PREPAY_ACCT_TYPE && amount >0){
				double prepaySum = chainFinanceTraceImpl.getSumOfFinanceCategory(FinanceCategory.PREPAY_ACCT_TYPE, custId) + cust.getPrepayInitialAmount();
			    if (amount > prepaySum){
			    	response.setQuickValue(Response.FAIL, "预付款超过以前总和");
			    	return false;
			    }
			}
		}
		
		return true;
	}

	/***
	 * to delete the FHQ Bill
	 * @param financeBill
	 */
	public Response deleteFHQBill(FinanceBill financeBill) {
		Response response = new Response();
		int billId = financeBill.getId();
		FinanceBill originalBill = financeBillImpl.get(billId, true);
		
		if (originalBill != null && originalBill.getStatus() == FinanceBill.STATUS_DRAFT){
			originalBill.setStatus(FinanceBill.STATUS_DELETED);
			originalBill.setCreateDate(new Date());
		
		    financeBillImpl.saveOrUpdate(originalBill, true);
		    
		    response.setReturnCode(Response.SUCCESS);
		} else {
			response.setReturnCode(Response.ERROR);
			response.setMessage("删除单据出错");
		}
		
		return response;
	}
	
	/**
	 * service to cancel the bill 
	 * 
	 * src : 上游操作他的动作
	 * 1 : 单据通过financeBill 手动红冲
	 * 2 : 单据通过自动红冲
	 * @param financeBill
	 * @throws ParseException 
	 */
	@Transactional
	public Response cancelFHQBill(FinanceBill financeBill, UserInfor user, int src) throws ParseException {
		Response response = new Response();
		int billId = financeBill.getId();
		FinanceBill originalBill = financeBillImpl.get(billId, true);
		
		if (originalBill == null || originalBill.getStatus() != FinanceBill.STATUS_COMPLETE){
			response.setReturnCode(Response.ERROR);
			response.setMessage("单据不存在或者尚未过账无法红冲");
		} else {
			//1.0 如果这张单据是根据某张销售单据自动生成，那么不能单独红冲
		    int inventoryOrderId = originalBill.getInventoryOrderId();
		    if (inventoryOrderId != 0 && src == 1){
		    	response.setFail("当前单据是销售单据过账自动生成。请红冲 销售单据" + inventoryOrderId +",此单据会自动红冲");
		    	return response;
		    }
			
			//2.0 change the bill status 
			originalBill.setStatus(FinanceBill.STATUS_CANCEL);
			originalBill.setCreatorHq(user);
			
			//originalBill.setCreateDate(new Date());	
			financeBillImpl.update(originalBill, true);

			//3.0 updat the finance trace
			updateFinanceTrace(originalBill, true);

			//4.0 update the acct flow
			updateChainAcctFlow(originalBill, true);
			
			//5.0更新客户表账目
			HeadQCust cust = headQCustDaoImpl.get(financeBill.getCust().getId(), true);
			updateCustAcctBalance(cust);

			response.setReturnCode(Response.SUCCESS);
		}
		
		return response;
	}
	
	/**
	 * service to cancel the bill 
	 * @param financeBill
	 * @throws ParseException 
	 */
	@Transactional
	public Response cancelFHQBill(FinanceBill financeBill) throws ParseException {
		Response response = new Response();
		int billId = financeBill.getId();
		FinanceBill originalBill = financeBillImpl.get(billId, true);
		
		if (originalBill == null || originalBill.getStatus() != FinanceBill.STATUS_COMPLETE){
			response.setReturnCode(Response.ERROR);
			response.setMessage("单据不存在或者尚未过账无法红冲");
		} else {
		
			//判断单据时间是否超过规定的清账时间之前
			Date accountFlowDate = SystemParm.getAccountFlowDate();
			if (originalBill.getBillDate().before(accountFlowDate)) {
				response.setReturnCode(Response.ERROR);
				response.setMessage("无法红冲：" + Common_util.dateFormat.format(SystemParm.getAccountFlowDate()) + "之前的单据");
			}else {
				//1.0 change the bill status 
				originalBill.setStatus(FinanceBill.STATUS_CANCEL);
				originalBill.setUpdateDate(new Date());	
				financeBillImpl.update(originalBill, true);

				//2.0 updat the finance trace
				updateFinanceTrace(originalBill, true);

				//3.0 update the acct flow
				updateChainAcctFlow(originalBill, true);
				
				//4.0 更新finance category flow  红冲
				financeCategoryFlowDaoImpl.updateFinanceCategoryFlow(null,originalBill,true,false);
				

				//5.0更新客户表账目
				updateCustAcctBalance(originalBill.getCust());

				response.setReturnCode(Response.SUCCESS);
			}
					
		}
		
		return response;
	}
	
	/**
	 * function to search the finance bills based on the search criteria
	 * 
	 * 连锁店端口查询财务单据
	 * @param formBean
	 * @return
	 */
	public List<FinanceBill> searchFHQBills(FinanceActionFormBean formBean, ChainUserInfor userInfor) {
		boolean cached = false;
		Pager pager = formBean.getPager();

		if (pager.getTotalPage() == 0){
		    DetachedCriteria criteria = buildSearchFHQBillsChain(formBean,userInfor);
			criteria.setProjection(Projections.rowCount());
			int totalRecord = Common_util.getProjectionSingleValue(financeBillImpl.getByCriteriaProjection(criteria, false));
			pager.initialize(totalRecord);
		} else {
			pager.calFirstResult();
			cached = true;
		}
		
		DetachedCriteria criteria2 = buildSearchFHQBillsChain(formBean, userInfor);
		criteria2.add(Restrictions.between("billDate", formBean.getSearchStartTime(), formBean.getSearchEndTime()));
		criteria2.addOrder(Order.asc("cust.id"));
		criteria2.addOrder(Order.asc("billDate"));
		
		return financeBillImpl.getByCritera(criteria2, pager.getFirstResult(), pager.getRecordPerPage(), cached);
	}
	
	private DetachedCriteria buildSearchFHQBillsChain(FinanceActionFormBean formBean, ChainUserInfor userInfor){
	
        DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
        FinanceBill financeBill = formBean.getFinanceBill();
		
		//1. 连锁店端口只能看完成状态
		criteria.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));

		
		//2. get the category
		int type = financeBill.getType();
		if (type != Common_util.ALL_RECORD)
			criteria.add(Restrictions.eq("type", type));
		
		
		//2. get the chain

		int clientId = formBean.getChainStore().getClient_id();
		if (clientId != Common_util.ALL_RECORD)
				criteria.add(Restrictions.eq("cust.id", clientId));
		else {
			if (clientId == Common_util.ALL_RECORD && ChainUserInforService.isMgmtFromHQ(userInfor)) {
				criteria.add(Restrictions.isNotNull("chainStore"));
			} else {
				criteria.add(Restrictions.eq("cust.id", userInfor.getMyChainStore().getClient_id()));
			}
		}
	
			
		
		//4. set the date
		Date startDate = Common_util.formStartDate(formBean.getSearchStartTime());
		Date endDate = Common_util.formEndDate(formBean.getSearchEndTime());
		criteria.add(Restrictions.between("billDate", startDate, endDate));
		
		return criteria;
	}

	/**
	 * function to search the finance bills based on the search criteria
	 * 
	 * 总部端口查询财务单据
	 * @param formBean
	 * @return
	 */
	public Response searchFHQBills(FinanceActionFormBean formBean,int page, int rowPerPage, String sort, String order) {
		Response response = new Response();
		boolean cached = false;
		Map data = new HashMap<String, Object>();
		List<FinanceBillCustomerVO> list = new ArrayList<FinanceBillCustomerVO>();
		List<FinanceBillCustomerVO> footers = new ArrayList<FinanceBillCustomerVO>();
		FinanceBillCustomerVO footer = new FinanceBillCustomerVO();
		
		int totalRecord = 0;

		DetachedCriteria criteria = buildSearchFHQBills(formBean);
		criteria.setProjection(Projections.rowCount());
		totalRecord = Common_util.getProjectionSingleValue(financeBillImpl.getByCriteriaProjection(criteria, false));

		DetachedCriteria criteria2 = buildSearchFHQBills(formBean);
		
		DetachedCriteria criteriaTotal = buildSearchFHQBills(formBean);
				
		if (StringUtils.isNotBlank(sort)) {
			if (order.equals("asc")) {
				criteria2.addOrder(Order.asc(sort));
			}else {
				criteria2.addOrder(Order.desc(sort));
			}			
		}
			
		List<FinanceBill> fList = financeBillImpl.getByCritera(criteria2, Common_util.getFirstRecord(page, rowPerPage),rowPerPage, cached);
		
		if (fList.size() !=0) {
			for (FinanceBill financeBill : fList) {
				FinanceBillCustomerVO financeBillCustomerVO = new FinanceBillCustomerVO(financeBill);
				list.add(financeBillCustomerVO);
			}
		}
		// 获取合计sumBalance
		criteriaTotal.setProjection(Projections.sum("invoiceTotal"));
		//TODO: 2025.7.4
		Object sumObj = financeBillImpl.getByCriteriaProjection(criteriaTotal, true).get(0);  
		
		double sumInvoiceTotal = 0;
		if (sumObj != null) {
			sumInvoiceTotal = (Double) sumObj;
		}
		footer.setCustName("合计");
		footer.setInvoiceTotal(Double.toString(Common_util.formatDouble(sumInvoiceTotal, Common_util.df2)));
		footers.add(footer);
		
		data.put("rows", list);
		data.put("total", totalRecord);
		data.put("footer", footers);
		
		response.setReturnValue(data);

		return response;
	}
	
	private DetachedCriteria buildSearchFHQBills(FinanceActionFormBean formBean){
        DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
        FinanceBill financeBill = formBean.getFinanceBill();
		
		//1. get the status
		int status = Common_util.checkAllRecordValue(financeBill.getStatus());
		if (status != Common_util.ALL_RECORD)
			criteria.add(Restrictions.eq("status", status));
		else 
			criteria.add(Restrictions.ne("status", FinanceBill.STATUS_DELETED));
		
		//2. get the category
		int type = Common_util.checkAllRecordValue(financeBill.getType());
		if (type != Common_util.ALL_RECORD)
			criteria.add(Restrictions.eq("type", type));
				
		//2. get the chain
		int custId = Common_util.checkAllRecordValue(formBean.getHeadQCust().getId());
		if (custId != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("cust.id", custId));
		}
						
		//4. set the date
		Date startDate = Common_util.formStartDate(formBean.getSearchStartTime());
		Date endDate = Common_util.formEndDate(formBean.getSearchEndTime());
		criteria.add(Restrictions.between("billDate", startDate, endDate));
		
		return criteria;
	}
	
	/**
	 * to update the finance trace
	 * @param bill
	 * @param isCancel
	 */
	private void updateFinanceTrace(FinanceBill bill, boolean isCancel){
		//int chainId = bill.getChainStore().getChain_id();
		// 修改chainId为custId  
		int custId = bill.getCust().getId();
		int chainId = 0;
		ChainStore chainStore = chainStoreDaoImpl.getByClientId(custId);
		if (chainStore != null)
			chainId = chainStore.getChain_id();
		
		String billId = String.valueOf(bill.getId());
		int offset = isCancel ? -1 : 1;
		billId= isCancel ? "C" + billId : billId;
		
		int billType = bill.getType();
		
		//if it is 总部的付款单需要*-1
		if (billType == FinanceBill.FINANCE_PAID_HQ || billType == FinanceBill.FINANCE_INCREASE_HQ)
			offset *= -1;
		
		double totalAmt = 0;
		//1. to update the bill items
		for (FinanceBillItem billItem : bill.getFinanceBillItemSet()){
			int categoryId = billItem.getFinanceCategory().getId();
			int type = financeCategoryImpl.get(categoryId, true).getType();
			double amount = billItem.getTotal();
			
			if (amount != 0){
				totalAmt += amount;
				//1.1 if it is 预付款需要减
				if (type == FinanceCategory.PREPAY_ACCT_TYPE)
					offset *= -1;
				
				// 这里为有参构造函数，第一个参数为custId;
				ChainFinanceTrace financeTrace = chainFinanceTraceImpl.getByPK(custId,chainId, type, billId);
				if (financeTrace == null)
			           financeTrace = new ChainFinanceTrace(custId,chainId, type, billId, amount * offset, new java.sql.Date(bill.getBillDate().getTime()));
				else {
					double amt = financeTrace.getAmount();
					amt += amount * offset;
					financeTrace.setAmount(amt);
				}
				
				chainFinanceTraceImpl.saveOrUpdate(financeTrace, false);
			} 
		}
		
		//2. if it is prepaid bill, need insert a prepaid amount
		if (billType == FinanceBill.FINANCE_PREINCOME_HQ){
		    ChainFinanceTrace financeTrace = new ChainFinanceTrace(custId,chainId, FinanceCategory.PREPAY_ACCT_TYPE, billId, totalAmt * offset , new java.sql.Date(bill.getCreateDate().getTime()));
		    chainFinanceTraceImpl.save(financeTrace, false);
		}
		
	}
	
	private void updateChainAcctFlow(FinanceBill bill, boolean isCancel){
		//int chainId = bill.getChainStore().getChain_id();
		// 修改chainId为custId  
		int custId = bill.getCust().getId();
		//ChainStore chainStore = chainStoreDaoImpl.get(chainId, true);
		HeadQCust hCust = headQCustDaoImpl.get(custId,true);
		if (hCust !=  null){
			int billType = bill.getType();
			int offset = 1;
			
			//1. check the finance bill type
			if (billType == FinanceBill.FINANCE_INCOME_HQ || billType == FinanceBill.FINANCE_DECREASE_HQ || billType == FinanceBill.FINANCE_PREINCOME_SPEND_HQ){
				offset *= -1;
			} else if (billType == FinanceBill.FINANCE_PAID_HQ || billType == FinanceBill.FINANCE_INCREASE_HQ){
				offset *= 1;
			}  else {
				offset *= 0;
			}
			
			//2. check is cancel
			if (isCancel)
				offset *= -1;
			
			//3. calculate the pre-acct and postAcctAmt
    		//double initialAcctAmt = chainStore.getInitialAcctAmt();
			double initialAcctAmt = hCust.getInitialAcctBalance();
			// 这里为连锁店时候调用getAccumulateAcctFlow 方法
    		double acctAmtFlow = chainAcctFlowDaoImpl.getAcctFlowByCustId(custId);
    		double preAcctAmt = Common_util.getDecimalDouble(initialAcctAmt + acctAmtFlow);
    		
    		//4. 设计折扣
    		double invoiceTotal = bill.getInvoiceTotal();
			if (billType == FinanceBill.FINANCE_INCREASE_HQ || billType == FinanceBill.FINANCE_PAID_HQ) {
				invoiceTotal -= bill.getInvoiceDiscount();
			} else if (billType == FinanceBill.FINANCE_DECREASE_HQ || billType == FinanceBill.FINANCE_INCOME_HQ){
				invoiceTotal += bill.getInvoiceDiscount();
			}
			double netAmt = offset * invoiceTotal;
			double postAcctAmt = Common_util.getDecimalDouble(preAcctAmt + netAmt);
    		
    		//4.update the finance bill's pre and post 
    		if (!isCancel){
    		   bill.setPreAcctAmt(preAcctAmt);
    		   bill.setPostAcctAmt(postAcctAmt);
    		   financeBillImpl.update(bill, true);
    		}
    		
    		int chainId = 0;
    		ChainStore chainStore = chainStoreDaoImpl.getByClientId(custId);
    		if (chainStore != null)
    			chainId = chainStore.getChain_id();
    		
			
			ChainAcctFlow chainAcctFlow = new ChainAcctFlow(custId, netAmt, "F," + bill.getId() + "," + isCancel, new java.sql.Date(bill.getBillDate().getTime()), chainId);
			chainAcctFlowDaoImpl.save(chainAcctFlow, true);
		}
		
	}

	/**
	 * to get the finance bill by id
	 * @param id
	 * @return
	 */
	@Transactional
	public FinanceBill getFinanceBillById(int id) {
		FinanceBill financeBill = financeBillImpl.get(id, true);
		
		financeBillImpl.initialize(financeBill);
		
		financeBill.putSetToList();
		
		return financeBill;
	}

	/**
	 * 获取连锁店当前欠款 和 预付款
	 * @param chainId
	 * @return
	 * @throws ParseException 
	 */
	public Response getChainCurrentFinance(int chainId) throws ParseException {
		Response response = new Response();
		
		ChainStore chainStore = chainStoreDaoImpl.get(chainId, true);
		
		//1. Get the current finance
		double initialAcct = chainStore.getInitialAcctAmt();
		double currentFinance = initialAcct + chainAcctFlowDaoImpl.getAcctFlowByCustId(chainStore.getClient_id());
		currentFinance = Common_util.roundDouble(currentFinance, 2);
		
		//2. get the accumulated prepaid
		double prepaid = chainFinanceTraceImpl.getSumOfFinanceCategory(FinanceCategory.PREPAY_ACCT_TYPE, chainId);
		prepaid = Common_util.roundDouble(prepaid, 2);
		
		response.setReturnCode(Response.SUCCESS);
		
		Map<String, Double> financeDataMap = new HashMap<String, Double>();
		financeDataMap.put("cf", currentFinance);
		financeDataMap.put("pp", prepaid);
		
		response.setReturnValue(financeDataMap);
		
		return response;
	}
	
	
	/**
	 * 获取连锁店当前欠款 和 预付款
	 * @param chainId
	 * @return
	 * @throws ParseException 
	 */
	public Response getHeadCustFinance(int custId) throws ParseException {
		Response response = new Response();
		
		HeadQCust cust = headQCustDaoImpl.get(custId, true);
		
		//1. Get the current finance期初欠款
		double initialAcct = cust.getInitialAcctBalance();
		
	    //2.当前欠款
		double currentFinance = initialAcct + chainAcctFlowDaoImpl.getAcctFlowByCustId(custId);
		currentFinance = Common_util.roundDouble(currentFinance, 2);
		
		//2. get the accumulated prepaid
		double prepaid = chainFinanceTraceImpl.getSumOfFinanceCategory(FinanceCategory.PREPAY_ACCT_TYPE, custId);
		prepaid = Common_util.roundDouble(prepaid, 2);
		
		response.setReturnCode(Response.SUCCESS);
		
		Map<String, Double> financeDataMap = new HashMap<String, Double>();
		financeDataMap.put("cf", currentFinance);
		financeDataMap.put("pp", prepaid);
		
		response.setReturnValue(financeDataMap);
		
		return response;
	}

	/**
	 * 
	 * @param startDate
	 * @param endDate
	 * @param chainId
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Response searchAcctFlow(Date startDate,Date endDate,int custId ,String tagGroups, boolean isChain) {
		Response response = new Response();
		List<ChainAcctFlowReportItem> rptItems = new ArrayList<ChainAcctFlowReportItem>();
		List<Integer> orderCliendIds =  new ArrayList<Integer>(); 	
		List<Integer> billIds = new ArrayList<Integer>();
		List<Integer> custIds = new ArrayList<Integer>();
		if (StringUtils.isNotBlank(tagGroups)) {
			custIds = headQCustDaoImpl.getTagGroupsCusts(tagGroups);			
		}

		/**
		 * 1. 搜索所有采购单据
		 */
		List<InventoryOrder> purchaseOrders = new ArrayList<InventoryOrder>();
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");
		criteria.add(Restrictions.eq("order.order_Status", InventoryOrder.STATUS_ACCOUNT_COMPLETE));

		if (custId != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("order.client_id", custId));
			criteria.add(Restrictions.between("order.order_EndTime", Common_util.formStartDate(startDate), Common_util.formEndDate(endDate)));
			purchaseOrders = inventoryOrderDAOImpl.getByCritera(criteria, true);
		}else if(StringUtils.isNotBlank(tagGroups)) {
			orderCliendIds = inventoryOrderDAOImpl.selectCIdsByBetweenTime(startDate,endDate);
			if (orderCliendIds != null) {
				orderCliendIds.retainAll(custIds);
			} 
			if (orderCliendIds.size() !=0) {
				criteria.add(Restrictions.in("order.client_id", orderCliendIds));				
				criteria.add(Restrictions.between("order.order_EndTime", Common_util.formStartDate(startDate), Common_util.formEndDate(endDate)));
				purchaseOrders = inventoryOrderDAOImpl.getByCritera(criteria, true);
			}	
		}else {
			criteria.add(Restrictions.between("order.order_EndTime", Common_util.formStartDate(startDate), Common_util.formEndDate(endDate)));
			purchaseOrders = inventoryOrderDAOImpl.getByCritera(criteria, true);
		}
		
		/**
		 * 2. 搜索所有财物单据
		 */
		List<FinanceBill> financeBills = new ArrayList<FinanceBill>();
		DetachedCriteria criteria2 = DetachedCriteria.forClass(FinanceBill.class);
		criteria2.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));
		if (custId != Common_util.ALL_RECORD) {
			criteria2.add(Restrictions.eq("cust.id", custId));
			criteria2.add(Restrictions.between("billDate", startDate, endDate));
			financeBills = financeBillImpl.getByCritera(criteria2, true);
		}else if(StringUtils.isNotBlank(tagGroups)){
			 billIds = financeBillImpl.selectCIdsByBetweenTime(startDate,endDate);
			 if (billIds != null) {
					billIds.retainAll(custIds);
				} 	
			 if (billIds.size() !=0) {
				criteria2.add(Restrictions.in("cust.id", billIds));
				criteria2.add(Restrictions.between("billDate", startDate, endDate));
				financeBills = financeBillImpl.getByCritera(criteria2, true);
			}			
		}else {
			criteria2.add(Restrictions.between("billDate", startDate, endDate));
			financeBills = financeBillImpl.getByCritera(criteria2, true);
		}
	
		constructChainAcctFlowRptItems(purchaseOrders, financeBills, rptItems, custId,custIds, isChain, startDate);

		Map data = new HashMap<String, List>();
		data.put("rows", rptItems);
		response.setReturnValue(data);
		response.setReturnCode(Response.SUCCESS);

		return response;
	}
	
	/**
	 * 构建账户流水
	 * @param purchaseOrders
	 * @param financeBills
	 * @param rptItems
	 */
	private void constructChainAcctFlowRptItems(List<InventoryOrder> purchaseOrders, List<FinanceBill> financeBills, List<ChainAcctFlowReportItem> rptItems, int clientId,List<Integer> clientIds, boolean isChain, Date startDate){
		//1. 货品采购单
		if (purchaseOrders !=null && purchaseOrders.size() >0){
			for (InventoryOrder order : purchaseOrders){
				HeadQCust cust = headQCustDaoImpl.get(order.getClient_id(), true);
				String orderType = "";
				String comment = order.getComment();
				if (isChain) {
					orderType = order.getOrder_type_chain();
				} else {
					orderType = order.getOrder_type_ws();
					comment += "<br/>" + order.getComment2();
				}
				
				String acctFlowType ="";
				if (order.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE;
				else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_RETURN_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE;
				else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_FREE_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_NOCHANGE;
				
				ChainAcctFlowReportItem acctFlowItem = new ChainAcctFlowReportItem(cust, order.getOrder_EndTime(), orderType, ChainAcctFlowReportItem.ITEM_TYPE_PURCHASE,acctFlowType, order.getTotalQuantity(), order.getTotalWholePrice() - order.getTotalDiscount(), order.getOrder_ID(),comment, 0,0);
				rptItems.add(acctFlowItem);
			}
		}
		
		//2. 财务单据
		if (financeBills != null && financeBills.size() > 0){
			for (FinanceBill bill : financeBills){
				HeadQCust cust = bill.getCust();
				String billTypeName = "";
				if (isChain)
					billTypeName = bill.getTypeChainS();
				else 
					billTypeName = bill.getTypeHQS();
				
				int billType = bill.getType();
				String acctFlowType = "";
				double invoiceTotal = bill.getInvoiceTotal();
				if (billType == FinanceBill.FINANCE_INCREASE_HQ || billType == FinanceBill.FINANCE_PAID_HQ ) {
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE;
					invoiceTotal -= bill.getInvoiceDiscount();
				} else if (billType == FinanceBill.FINANCE_DECREASE_HQ || billType == FinanceBill.FINANCE_INCOME_HQ || billType == FinanceBill.FINANCE_PREINCOME_SPEND_HQ){
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE;
					invoiceTotal += bill.getInvoiceDiscount();
				}
				
				ChainAcctFlowReportItem acctFlowItem = new ChainAcctFlowReportItem(cust, bill.getBillDate(), billTypeName, ChainAcctFlowReportItem.ITEM_TYPE_FINANCE, acctFlowType, 0, invoiceTotal, bill.getId(), bill.getComment(), 0,0);
				rptItems.add(acctFlowItem);
			}
		}
		
		//3. 排序一下
		Collections.sort(rptItems, new ChainAcctFlowReportItemSort());
		
		//4. 获取前面的累计欠款
		Date firstDate = null;
		double acctBefore = 0;
		if (rptItems.size() > 0){
			firstDate = rptItems.get(0).getDate();
		} else 
			firstDate = startDate;
			
		
		if (firstDate != null && clientIds.size() !=0) {
		    acctBefore = chainAcctFlowDaoImpl.getAccumulateAcctFlowBefore(clientIds, firstDate);
			double initialAcctBalance = headQCustDaoImpl.selectInitialAcctByIds(clientIds);
			acctBefore +=initialAcctBalance;
		}else {
			acctBefore = chainAcctFlowDaoImpl.getAccumulateAcctFlowBefore(clientId, firstDate);
			HeadQCust cust = headQCustDaoImpl.get(clientId, true);
			if (cust != null) {
				acctBefore +=cust.getInitialAcctBalance();
			}
		}
		if (clientId == Common_util.ALL_RECORD && clientIds.size() == 0) {
			acctBefore = chainAcctFlowDaoImpl.getBeforeDateSumAcctAmt(Common_util.formStartDate(firstDate));
		}

		double acctAfter = acctBefore;
		for (ChainAcctFlowReportItem rptItem: rptItems){
			double thisAmt = rptItem.getAmount();
			String acctFlowType = rptItem.getAcctFlowType();
			
			if (acctFlowType.equalsIgnoreCase(ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE)){
				acctAfter += thisAmt;
				rptItem.setAcctIncrease(thisAmt);
				rptItem.setPostAcct(acctAfter);
			} else if (acctFlowType.equalsIgnoreCase(ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE)){
				acctAfter = acctAfter - thisAmt;
				rptItem.setAcctDecrease(thisAmt);
				rptItem.setPostAcct(acctAfter);
			} else {
				rptItem.setPostAcct(acctAfter);
			}

		}
		
		//5.0 设置首
		ChainAcctFlowReportItem firstItem = new ChainAcctFlowReportItem();
		HeadQCust fiCust = new HeadQCust();
		Date staDate = Common_util.formStartDate(startDate);
		fiCust.setName(Common_util.dateFormat_f.format(staDate)+":前欠款金额");
		firstItem.setCust(fiCust);
		firstItem.setPostAcct(acctBefore);
		rptItems.add(0, firstItem);

	}
	
	/**
	 * 
	 * @param startDate
	 * @param endDate
	 * @param chainId
	 * @return
	 */
	public List<ChainAcctFlowReportItem> searchAcctFlowByExcleDownload(Date startDate, Date endDate, int custId,
			boolean isChain) {

		List<ChainAcctFlowReportItem> rptItems = new ArrayList<ChainAcctFlowReportItem>();
		/**
		 * 1. 搜索所有采购单据
		 */
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");
		criteria.add(Restrictions.eq("order.order_Status", InventoryOrder.STATUS_ACCOUNT_COMPLETE));

		if (custId != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("order.client_id", custId));
		} 
		
		startDate = Common_util.formStartDate(startDate);
		endDate = Common_util.formEndDate(endDate);
		criteria.add(Restrictions.between("order.order_EndTime", startDate, endDate));
		List<InventoryOrder> purchaseOrders = inventoryOrderDAOImpl.getByCritera(criteria, true);

		/**
		 * 2. 搜索所有财物单据
		 */
		DetachedCriteria criteria2 = DetachedCriteria.forClass(FinanceBill.class);
		criteria2.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));
		if (custId != Common_util.ALL_RECORD){
			criteria2.add(Restrictions.eq("cust.id", custId));
		} 
		
		criteria2.add(Restrictions.between("billDate", startDate, endDate));
		List<FinanceBill> financeBills = financeBillImpl.getByCritera(criteria2, true);
		

		constructChainAcctFlowRptItems(purchaseOrders, financeBills, rptItems, custId, isChain, startDate);

		return rptItems;
	}

	/**
	 * 构建账户流水
	 * @param purchaseOrders
	 * @param financeBills
	 * @param rptItems
	 */
	private void constructChainAcctFlowRptItems(List<InventoryOrder> purchaseOrders, List<FinanceBill> financeBills, List<ChainAcctFlowReportItem> rptItems, int clientId, boolean isChain, Date startDate){
		//1. 货品采购单
		if (purchaseOrders !=null && purchaseOrders.size() >0){
			for (InventoryOrder order : purchaseOrders){
				HeadQCust cust = headQCustDaoImpl.get(order.getClient_id(), true);
				String orderType = "";
				String comment = order.getComment();
				if (isChain) {
					orderType = order.getOrder_type_chain();
				} else {
					orderType = order.getOrder_type_ws();
					comment += "<br/>" + order.getComment2();
				}
				
				String acctFlowType ="";
				if (order.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE;
				else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_RETURN_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE;
				else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_FREE_ORDER_W)
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_NOCHANGE;
				
				ChainAcctFlowReportItem acctFlowItem = new ChainAcctFlowReportItem(cust, order.getOrder_EndTime(), orderType, ChainAcctFlowReportItem.ITEM_TYPE_PURCHASE,acctFlowType, order.getTotalQuantity(), order.getTotalWholePrice() - order.getTotalDiscount(), order.getOrder_ID(),comment, 0,0);
				rptItems.add(acctFlowItem);
			}
		}
		
		//2. 财务单据
		if (financeBills != null && financeBills.size() > 0){
			for (FinanceBill bill : financeBills){
				HeadQCust cust = bill.getCust();
				String billTypeName = "";
				if (isChain)
					billTypeName = bill.getTypeChainS();
				else 
					billTypeName = bill.getTypeHQS();
				
				int billType = bill.getType();
				String acctFlowType = "";
				double invoiceTotal = bill.getInvoiceTotal();
				if (billType == FinanceBill.FINANCE_INCREASE_HQ || billType == FinanceBill.FINANCE_PAID_HQ ) {
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE;
					invoiceTotal -= bill.getInvoiceDiscount();
				} else if (billType == FinanceBill.FINANCE_DECREASE_HQ || billType == FinanceBill.FINANCE_INCOME_HQ || billType == FinanceBill.FINANCE_PREINCOME_SPEND_HQ){
					acctFlowType = ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE;
					invoiceTotal += bill.getInvoiceDiscount();
				}
				
				ChainAcctFlowReportItem acctFlowItem = new ChainAcctFlowReportItem(cust, bill.getBillDate(), billTypeName, ChainAcctFlowReportItem.ITEM_TYPE_FINANCE, acctFlowType, 0, invoiceTotal, bill.getId(), bill.getComment(), 0,0);
				rptItems.add(acctFlowItem);
			}
		}
		
		//3. 排序一下
		Collections.sort(rptItems, new ChainAcctFlowReportItemSort());
		
		//4. 获取前面的累计欠款
		Date firstDate = null;
		double acctBefore  = 0;
		if (rptItems.size() > 0){
			firstDate = rptItems.get(0).getDate();
		} else 
			firstDate = startDate;
			
		
		if (firstDate != null)
		    acctBefore = chainAcctFlowDaoImpl.getAccumulateAcctFlowBefore(clientId, firstDate);
		
		//5. 准备数据
        //优先使用连锁店的期初欠款
		ChainStore store = chainStoreDaoImpl.getByClientId(clientId);
		if (store != null) {
			acctBefore += store.getInitialAcctAmt();
			loggerLocal.info(store.getChain_name() + " 使用 期初欠款  : " + acctBefore);
		} else {
			HeadQCust cust = headQCustDaoImpl.get(clientId, true);
		    if (cust != null) {
		        acctBefore += cust.getInitialAcctBalance();
		        loggerLocal.info(cust.getName() + " 使用 期初欠款  : " + acctBefore);
		    }
		}
		
		double acctAfter = acctBefore;
		for (ChainAcctFlowReportItem rptItem: rptItems){
			double thisAmt = rptItem.getAmount();
			String acctFlowType = rptItem.getAcctFlowType();
			
			if (acctFlowType.equalsIgnoreCase(ChainAcctFlowReportItem.ACCT_FLOW_TYPE_INCREASE)){
				acctAfter += thisAmt;
				rptItem.setAcctIncrease(thisAmt);
				rptItem.setPostAcct(acctAfter);
			} else if (acctFlowType.equalsIgnoreCase(ChainAcctFlowReportItem.ACCT_FLOW_TYPE_DECREASE)){
				acctAfter = acctAfter - thisAmt;
				rptItem.setAcctDecrease(thisAmt);
				rptItem.setPostAcct(acctAfter);
			} else {
				rptItem.setPostAcct(acctAfter);
			}

		}
		
		//6.0 设置首
		ChainAcctFlowReportItem firstItem = new ChainAcctFlowReportItem();
		firstItem.setDate(startDate);
		firstItem.setPostAcct(acctBefore);
		rptItems.add(0, firstItem);
	}
	
	
	private Set<Integer> getAllChainId(){
		Set<Integer> chainIds = new HashSet<Integer>();
		List<ChainStore> stores = chainStoreService.getAvailableClientChainstores();
		for (ChainStore chainStore : stores)
			chainIds.add(chainStore.getChain_id());
		
		return chainIds;
	}
	
	private Set<Integer> getAllCustId(){
		Set<Integer> custIds = new HashSet<Integer>();
		List<HeadQCust> hList = headQCustDaoImpl.getAllHeadCust();
		for (HeadQCust hCust : hList)
			custIds.add(hCust.getId());
		
		return custIds;
	}
	
	private Set<Integer> getAllChainClientId(){
		Set<Integer> clientIds = new HashSet<Integer>();
		List<ChainStore> stores = chainStoreService.getAvailableClientChainstores();
		for (ChainStore chainStore : stores)
			clientIds.add(chainStore.getClient_id());
		
		return clientIds;
	}

	/**
	 * 生成客户往来账
	 * 
	 * @param string
	 * @param formBean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Response generateAcctFlowExcel(String path, FinanceActionFormBean formBean) {

		Response response = new Response();
		try {
			Date startDate = formBean.getSearchStartTime();
			loggerLocal.info(startDate.toString());
			Date endDate = formBean.getSearchEndTime();
			loggerLocal.info(endDate.toString());

			int clientId = formBean.getHeadQCust().getId();
			// 查询符合条件的数据			
			Map data  = (Map) searchAcctFlow(startDate, endDate, Common_util.checkAllRecordValue(clientId),formBean.getTagGroups(), false).getReturnValue();
			List<ChainAcctFlowReportItem> list = (List<ChainAcctFlowReportItem>) data.get("rows");
			ChainAcctFlowTemplate reportTemplate = new ChainAcctFlowTemplate(formBean.getSearchStartTime(),
					formBean.getSearchEndTime(), formBean.getHeadQCust().getName(), path, list);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	
	
	/**
	 * 导出应收账款明细
	 * 
	 * @param string
	 * @param formBean
	 * @return
	 */
	public Response generateAcctFlowDetailsExcel(String path, FinanceActionFormBean formBean) {
		Response response = new Response();
		List<ChainAcctFlowReportExcleVO> vos = new ArrayList<ChainAcctFlowReportExcleVO>();
		try {
			Date startDate = formBean.getSearchStartTime();
			loggerLocal.info(startDate.toString());
			Date endDate = formBean.getSearchEndTime();
			loggerLocal.info(endDate.toString());

			int clientId = formBean.getHeadQCust().getId();
			List<Integer> custByTagIds = new ArrayList<Integer>();
			if (StringUtils.isNotBlank(formBean.getTagGroups())) {
				custByTagIds = headQCustDaoImpl.getTagGroupsCusts(formBean.getTagGroups());			
			}
			//获取客户标签组集合信息
			List<Integer> groups = tagGroupDaoImpl.selectByGroup(HeadQTagGroup.GROUP_ONE);

			if (clientId != Common_util.ALL_RECORD_NEW) {
				ChainAcctFlowReportExcleVO vo = buildAcctFlowReportExcle(startDate,endDate,clientId,formBean.getHeadQCust().getName(),groups);
				vos.add(vo);
			}else {
				HashSet<Integer> custIds = new HashSet<Integer>();//所有客户
				//1.销售单据
				List<InventoryOrder> inventoryOrders = inventoryOrderDAOImpl.selectOrdersByEndTime(startDate,endDate,custByTagIds);
				if (inventoryOrders.size() !=0) {
					for (InventoryOrder inventoryOrder : inventoryOrders) {
						custIds.add(inventoryOrder.getClient_id());
					}
				}
				//2.财物单据
				List<FinanceBill> financeBills = financeBillImpl.selectBillsByDate(startDate,endDate,custByTagIds);
				if (financeBills.size() != 0) {
					for (FinanceBill bill : financeBills) {
						custIds.add(bill.getCust().getId());						
					}
				}				
				List<Integer> ids = new ArrayList<Integer>();
				if (custIds.size() != 0) {
					for (Integer id : custIds) {
						ids.add(id);
					}
				}
				List<HeadQCust> custs = headQCustDaoImpl.selectCustsByIds(ids);
				for (HeadQCust headQCust : custs) {
					ChainAcctFlowReportExcleVO vo = buildAcctFlowReportExcle(startDate,endDate,headQCust.getId(),headQCust.getName(),groups);
					vos.add(vo);
				}
			}		

			ChainAcctFlowDetailsTemplate reportTemplate = new ChainAcctFlowDetailsTemplate(formBean.getSearchStartTime(),formBean.getSearchEndTime(), formBean.getHeadQCust().getName(), path, vos);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	
	private ChainAcctFlowReportExcleVO buildAcctFlowReportExcle(Date startDate,Date endDate,int custId,String custName,List<Integer> groups) {
		
		ChainAcctFlowReportExcleVO vo = new ChainAcctFlowReportExcleVO();
		vo.setCustName(custName);
		//标签信息
		List<Integer> tags = headQEntityTagDaoImpl.selectTagsByCustId(custId);
		List<HeadQTag> sTags = headQTagDaoImpl.selectByIds(tags);

		if(sTags != null) {
			for (HeadQTag headQTag : sTags) {
				if (headQTag.getGroupId().getId() == groups.get(0)) {
					vo.setTagOne(headQTag.getTagName());
				}
				if (headQTag.getGroupId().getId() == groups.get(1)) {
					vo.setTagTwo(headQTag.getTagName());
				}
				if (headQTag.getGroupId().getId() == groups.get(2)) {
					vo.setTagThree(headQTag.getTagName());
				}
				if (headQTag.getGroupId().getId() == groups.get(3)) {
					vo.setTagFour(headQTag.getTagName());
				}		
			}
		}

				
		//期初金额
		double acctBefore = chainAcctFlowDaoImpl.getAccumulateAcctFlowBefore(custId, startDate);
        //优先使用连锁店的期初欠款
		ChainStore store = chainStoreDaoImpl.getByClientId(custId);
		if (store != null) {
			acctBefore += store.getInitialAcctAmt();
			loggerLocal.info(store.getChain_name() + " 使用 期初欠款  : " + acctBefore);
		} else {
			HeadQCust cust = headQCustDaoImpl.get(custId, true);
		    if (cust != null) {
		        acctBefore += cust.getInitialAcctBalance();
		        loggerLocal.info(cust.getName() + " 使用 期初欠款  : " + acctBefore);
		    }
		}
		vo.setBegain(acctBefore);
		/**
		 * 1.销售单据
		 */
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");
		criteria.add(Restrictions.eq("order.order_Status", InventoryOrder.STATUS_ACCOUNT_COMPLETE));

		criteria.add(Restrictions.eq("order.client_id", custId));					 				
		startDate = Common_util.formStartDate(startDate);
		endDate = Common_util.formEndDate(endDate);
		criteria.add(Restrictions.between("order.order_EndTime", startDate, endDate));
		List<InventoryOrder> inventoryOrders = inventoryOrderDAOImpl.getByCritera(criteria, true);
		if (inventoryOrders.size() !=0) {
			for (InventoryOrder inventoryOrder : inventoryOrders) {
				if (inventoryOrder.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W){
					vo.setSale(vo.getSale()+inventoryOrder.getTotalWholePrice()-inventoryOrder.getTotalDiscount());
				}else if (inventoryOrder.getOrder_type() == InventoryOrder.TYPE_SALES_RETURN_ORDER_W) {
					vo.setReturnGoods(vo.getReturnGoods()+inventoryOrder.getTotalWholePrice()-inventoryOrder.getTotalDiscount());
				}else if (inventoryOrder.getOrder_type() == InventoryOrder.TYPE_SALES_FREE_ORDER_W) {
					vo.setFree(vo.getFree()+inventoryOrder.getTotalWholePrice()-inventoryOrder.getTotalDiscount());
				}
			}
		}

		/**
		 * 2.财物单据
		 */
		DetachedCriteria criteria2 = DetachedCriteria.forClass(FinanceBill.class);
		criteria2.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));

		criteria2.add(Restrictions.eq("cust.id", custId));
		 				
		criteria2.add(Restrictions.between("billDate", startDate, endDate));
		List<FinanceBill> financeBills = financeBillImpl.getByCritera(criteria2, true);
		
		if (financeBills.size() != 0) {
			for (FinanceBill bill : financeBills) {
				int billType = bill.getType();
				double invoiceTotal = bill.getInvoiceTotal();
				if (billType == FinanceBill.FINANCE_INCREASE_HQ ) {
					invoiceTotal -= bill.getInvoiceDiscount();
					vo.setIncrease(vo.getIncrease() + invoiceTotal);
				} else if (billType == FinanceBill.FINANCE_PAID_HQ ){								
					invoiceTotal -= bill.getInvoiceDiscount();
					vo.setPayment(vo.getPayment() + invoiceTotal);						
				} else if (billType == FinanceBill.FINANCE_DECREASE_HQ ){							
					invoiceTotal += bill.getInvoiceDiscount();
					vo.setReduce(vo.getReduce() + invoiceTotal);
				} else if (billType == FinanceBill.FINANCE_INCOME_HQ ){							
					invoiceTotal += bill.getInvoiceDiscount();
					vo.setReceive(vo.getReceive() + invoiceTotal);
				}							
			}
		}	

		return vo;
	}
	
	/**
	 * 根据条件查询会计账目
	 * @param formBean
	 * @return
	 */
	public Response searchFinanceCategory(FinanceActionFormBean formBean) {
		Response response = new Response();
		String acctName = formBean.getFc().getItemName();
		int status = formBean.getFc().getStatus();
		int isTransferAccounts = formBean.getFc().getIsTransferAccounts();
		int belongTo2 = formBean.getFc().getBelongTo2();
		
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceCategory.class,"order");
		DetachedCriteria totalCriteria = DetachedCriteria.forClass(FinanceCategory.class,"order");
		if (!StringUtils.isBlank(acctName)) {
			criteria.add(Restrictions.like("itemName", acctName, MatchMode.ANYWHERE));
			totalCriteria.add(Restrictions.like("itemName", acctName, MatchMode.ANYWHERE));
		}
		if (status != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("status", status));
			totalCriteria.add(Restrictions.eq("status",status ));
		}
		if (isTransferAccounts != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("isTransferAccounts", isTransferAccounts));
			totalCriteria.add(Restrictions.eq("isTransferAccounts", isTransferAccounts));
		}
		if (belongTo2 != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("belongTo2", belongTo2));
			totalCriteria.add(Restrictions.eq("belongTo2", belongTo2));
		}
			criteria.addOrder(Order.asc("sort"));
		
		List<FinanceCategoryVO> categoryVOs = new ArrayList<FinanceCategoryVO>();
		List<FinanceCategory> categorys = financeCategoryImpl.getByCritera(criteria, false);

			if (categorys != null) {
				
				//账目流水信息
				Map<Integer, Double> acctFlowMap = financeCategoryFlowImpl.getAccumulateAcctFlowMap();
				
				for (FinanceCategory category : categorys) {					
					//千禧预收款账目
					if (category.getType() == FinanceCategory.PREPAY_ACCT_TYPE && category.getBelongTo2() == FinanceCategory.BELONG_TO_QX) {	
						List<Integer> qxCustIds = headQEntityTagDaoImpl.selectIdsByTagId(HeadQTag.HEADQ_QX_CUST_TAG_ID);
						//获取客户预存金sum = 所有客户期初预存金合计 + chainFinanceTrace预存金合计(预存金清账日期2025.3.1后合计金额）				
						Double advancePay = headQCustDaoImpl.selectPbAmount(FinanceCategory.BELONG_TO_XLC) + chainFinanceTraceImpl.getSumAdvancePay(SystemParm.getPrepayFlowDateS(),qxCustIds);
						FinanceCategoryVO vo = new FinanceCategoryVO(category, new Double(0),advancePay);
						categoryVOs.add(vo);
					}else if (category.getType() == FinanceCategory.PREPAY_ACCT_TYPE && category.getBelongTo2() == FinanceCategory.BELONG_TO_XLC) {	
						//禧乐仓预收款账目
						List<Integer> xlcCustIds = headQEntityTagDaoImpl.selectIdsByTagId(HeadQTag.HEADQ_XLC_CUST_TAG_ID);				
						Double advancePay = headQCustDaoImpl.selectPbAmount(FinanceCategory.BELONG_TO_XLC) + chainFinanceTraceImpl.getSumAdvancePay(null,xlcCustIds);
						FinanceCategoryVO vo = new FinanceCategoryVO(category, new Double(0),advancePay);
						categoryVOs.add(vo);
					}else {
						FinanceCategoryVO vo = new FinanceCategoryVO(category, acctFlowMap.get(category.getId()),new Double(0));
						categoryVOs.add(vo);
					}
				}
			}

		//1. 获取总条数
		totalCriteria.setProjection(Projections.rowCount());
		int total = Common_util.getProjectionSingleValue(financeCategoryImpl.getByCriteriaProjection(totalCriteria, true));
		
		
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("rows", categoryVOs);
		data.put("total", total);
		
		response.setReturnValue(data);
		
		return response;
	}

	/**
	 * 如果id 为空， 准备新增， 不为空，准备修改
	 * @param fc
	 * @return
	 */
	public Response editFinanceCategory(FinanceCategory fc) {
		Response response = new Response();
		List<Object> data = new ArrayList<Object>();
		//当前是添加新账户
		if (fc == null || fc.getId() == 0){
			return response;
		} else {
			
			int id = fc.getId();
			FinanceCategory fc2 = financeCategoryImpl.get(id, true);
			if (fc2 != null){
				Double accuAmt = financeCategoryFlowImpl.getAccumulateAcctFlow(id);
				data.add(fc2);
				data.add(accuAmt);
				response.setReturnValue(data);
				return response;
			} else {
				response.setFail("无法获取账目信息 : " + id);
				return response;
			}	
		}
	}
	
	/**
	 * 如果id 为空， 准备新增， 不为空，准备修改
	 * @param fc
	 * @return
	 */
	public Response editFinanceBillCorpFlow(FinanceActionFormBean formBean,FinanceActionUIBean uiBean, FinanceBillCorpFlow fCorpFlow) {
		Response response = new Response();

		List<FinanceCategory> financeCategoryList = selectIsTransferAccountsFc();
		uiBean.setFinanceCategory(financeCategoryList);
		
		//当前是增加新数据
		if (fCorpFlow == null || fCorpFlow.getId() == 0){

			return response;
		} else {
			int id = fCorpFlow.getId();
			FinanceBillCorpFlow financeBillCorpFlow = financeBillCoreFlowImpl.get(id, true);
			if (financeBillCorpFlow != null){
				formBean.setFinanceBillCorpFlow(financeBillCorpFlow);
				return response;
			} else {
				response.setFail("无法获取账目信息 : " + id);
				return response;
			}	
		}
	}

	/**
	 * 保存新的financeCategory 或者更新
	 * 
	 * 应收增加减少账户不能修改
	 * @param fc
	 * @return
	 */
	public Response createOrUpdateFinanceCategory(FinanceCategory fc,UserInfor userInfor) {
	Response response = new Response();
		
		try {
			//创建新的
			if (fc.getId() == 0){
				
				if (userInfor.getRoleType() != ChainRoleType.HEAD_ADMIN && fc.getType() !=0) {
					response.setFail("非正常账户，只有系统管理员客户可以创建");
				}else {
					fc.setCreateBy(userInfor.getUser_name());
					fc.setCreateTime(Common_util.getToday());
					financeCategoryImpl.save(fc, true);
					response.setSuccess("成功创建新的账目");
				}			
			} else {
				
				//更新旧的账目信息
				FinanceCategory fc2 = financeCategoryImpl.get(fc.getId(), true);
				if (fc2 == null){
					response.setFail("查找原账户信息失败 : 查找Id " + fc.getId());
				} else {

					if(fc2.getBelongTo() == FinanceCategory.BELONG_TO_SYSTEM) {
						
						if (fc.getIsTransferAccounts() == FinanceCategory.SUPPORT_TRANSFER_ACCOUNTS) {
							response.setFail("系统账户无法设置支持转账");
							return response;
						}
												
						if(userInfor.getRoleType() == ChainRoleType.HEAD_ADMIN ) {
							fc2.setType(fc.getType());
							fc2.setBelongTo(fc.getBelongTo());
						}else {
							response.setFail("系统账户仅限管理员修改");
							return response;
						}
					}
					
					
					fc2.setSort(fc.getSort());					
					fc2.setItemName(fc.getItemName());
					fc2.setStatus(fc.getStatus());
					fc2.setBelongTo2(fc.getBelongTo2());
					fc2.setIsTransferAccounts(fc.getIsTransferAccounts());
					fc2.setComment(fc.getComment());
					fc2.setLastUpdateBy(userInfor.getUser_name());
					fc2.setLastUpdateTime(Common_util.getToday());
					financeCategoryImpl.update(fc2, true);
					response.setSuccess("成功更新账户信息");
				}
			}
		} catch (Exception e){
			response.setFail("更新账户信息失败 : " + e.getMessage());
		}
		
		return response;
	}

	public void prepareSearchAcctFlowUI(FinanceActionUIBean uiBean, FinanceActionFormBean formBean,
			UserInfor userInfor) {
		
		formBean.setHeadQCust(HeadQCustDaoImpl.getAllHeadCustObject());
	}
	
	private DetachedCriteria buildCardDetailsCriteria(Date startDate, Date endDate, int cardId) throws ParseException {
		DetachedCriteria cardDetailsCriteria = DetachedCriteria.forClass(FinanceBillItem.class);
		DetachedCriteria categoryCriteria = cardDetailsCriteria.createCriteria("financeCategory");
		DetachedCriteria productCriteria = cardDetailsCriteria.createCriteria("financeBill");
	
		categoryCriteria.add(Restrictions.eq("id", cardId));
		productCriteria.add(Restrictions.eq("status",BaseOrder.STATUS_COMPLETE));

		productCriteria.add(Restrictions.between("billDate",startDate,endDate));
		return cardDetailsCriteria;
	}


	/*
	 * 根据账户id查询账户流水信息
	 */
	@Transactional
	public Map<String,Object> getCardFlowDetails(FinanceActionFormBean formBean) throws ParseException {
		Map<String,Object> data = new HashMap<String, Object>();
		
		Date startDate = formBean.getSearchStartTime();
		Date endDate = formBean.getSearchEndTime();
		int financeCategoryId = formBean.getFc().getId();
		
		FinanceCategory category = financeCategoryImpl.get(financeCategoryId, true);
		
		int financeCategoryType = formBean.getFinanceCategoryType();
		List<FinanceBillFlowDetailsVO> fDetailsVOs  = new ArrayList<FinanceBillFlowDetailsVO>();
		
		// 1.获取客户财务账号流水信息
		List<FinanceBillItem> order =  new ArrayList<FinanceBillItem>();
		
		//预存金账目流水
		if (category.getType() == FinanceCategory.PREPAY_ACCT_TYPE) {						
			fDetailsVOs = financeBillImpl.selectFlow(startDate,endDate,category);
			data.put("rows", fDetailsVOs);
			data.put("total",fDetailsVOs.size());
			return data;
		}else {
			//判断流水时间是否超过规定的清账时间之前,根据账目归属，来判断清账日期
			Date preDate = null;
			if (category.getBelongTo2() == FinanceCategory.BELONG_TO_QX) {
				preDate = SystemParm.getAccountFlowDate();
				if (startDate.before(preDate)) {
					startDate = SystemParm.getAccountFlowDate();
				}
			}else if (category.getBelongTo2() == FinanceCategory.BELONG_TO_XLC) {
				preDate = SystemParm.getXlcAccountFlowDate();
				if (startDate.before(preDate)) {
					startDate = SystemParm.getXlcAccountFlowDate();
				}
			}
			
			DetachedCriteria searchCritiera = buildCardDetailsCriteria(startDate, endDate, category.getId());
			order = financeBillItemImpl.getByCritera(searchCritiera, true);
		}		
		// 2.流水初始金额
		double sum = category.getInitialAmt();

		//非系统账户根据账目id获取该账目再startDate之前的合计金额
		sum += financeCategoryFlowDaoImpl.selectSumAmt(financeCategoryId,startDate);
			
		// 第一行 startTime之前的sum
		FinanceBillFlowDetailsVO fDetailsVO = new FinanceBillFlowDetailsVO();
		fDetailsVO.setFinanceCategoryName(category.getItemName());
		fDetailsVO.setBillDateS(startDate);
		//添加期初账目
		fDetailsVO.setBalance(sum);
		fDetailsVOs.add(fDetailsVO);
		
		// 1.客户账目
		if (financeCategoryType == FinanceCategory.CATEGORY_TYPE_CUST
				|| financeCategoryType == Common_util.ALL_RECORD) {

			if (order.size() > 0) {
				for (FinanceBillItem fItem : order) {
					if (fItem.getTotal() > 0) {
						FinanceBillFlowDetailsVO fVo = new FinanceBillFlowDetailsVO(fItem.getFinanceBill().getId(),
								fItem.getFinanceBill().getCust().getName(), FinanceCategory.ACCOUNT_TYPE_NAME_CUST, fItem.getTotal(), 0,
								fItem.getFinanceBill().getType(), fItem.getFinanceBill().getBillDate(),
								fItem.getFinanceBill().getComment(), fItem.getFinanceBill().getType(),fItem.getFinanceCategory());					
						fDetailsVOs.add(fVo);
					}

				}
			}
		}		
		
		// 2.供应商账目
		if (financeCategoryType == FinanceCategory.CATEGORY_TYPE_SUPPLIER
				|| financeCategoryType == Common_util.ALL_RECORD) {

			String sqlString = "SELECT FBSI FROM FinanceBillSupplierItem FBSI JOIN FBSI.financeBillSupplier FBS WHERE FBS.status = 2 AND FBS.billDate BETWEEN ? AND ? AND FBSI.financeCategory.id = ?";
			Object[] valuesObjects = new Object[] { startDate, endDate, financeCategoryId };
			List<FinanceBillSupplierItem> fList = financeBillSupplierItemDaoImpl.getByHQL(sqlString, valuesObjects,
					true);

			if (fList.size() > 0) {
				try {
					for (FinanceBillSupplierItem fItem : fList) {
						if (fItem.getTotal() > 0) {
							FinanceBillFlowDetailsVO fVo = new FinanceBillFlowDetailsVO(
									fItem.getFinanceBillSupplier().getId(),
									fItem.getFinanceBillSupplier().getSupplier().getName(), FinanceCategory.ACCOUNT_TYPE_NAME_SUPPLIER, fItem.getTotal(),
									0, fItem.getFinanceBillSupplier().getType(),
									fItem.getFinanceBillSupplier().getBillDate(),
									fItem.getFinanceBillSupplier().getComment(),
									fItem.getFinanceBillSupplier().getType(),fItem.getFinanceCategory());
							fDetailsVOs.add(fVo);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		}

		// 3.机构账目
		if (financeCategoryType == FinanceCategory.CATEGORY_TYPE_INSTITUTION || financeCategoryType == Common_util.ALL_RECORD) {
			List<FinanceBillCorpFlow> corpFlows = financeBillCoreFlowImpl.selectByCardId(financeCategoryId, startDate,endDate);
			if (corpFlows != null) {
				for (FinanceBillCorpFlow financeBillCorpFlow : corpFlows) {	
					//转出和转入机构为同一家
					if (financeCategoryId == financeBillCorpFlow.getFromAcctId().getId() && financeCategoryId == financeBillCorpFlow.getToAcctId().getId()) {
						FinanceBillFlowDetailsVO outVo = new FinanceBillFlowDetailsVO(financeBillCorpFlow,financeCategoryId,true);
						fDetailsVOs.add(outVo);	
						FinanceBillFlowDetailsVO enterVo = new FinanceBillFlowDetailsVO(financeBillCorpFlow,financeCategoryId,false);
						fDetailsVOs.add(enterVo);	
					}else {
						FinanceBillFlowDetailsVO vo = new FinanceBillFlowDetailsVO(financeBillCorpFlow,financeCategoryId);
						fDetailsVOs.add(vo);	
					}

				}
			}
		}
		
		// 4.总部账目
		if (financeCategoryType == FinanceCategory.CATEGORY_TYPE_HQ
				|| financeCategoryType == Common_util.ALL_RECORD) {
			List<ExpenseHqItem> list = expenseHqItemImpl.selectExpenseHqItems(startDate, endDate, Common_util.ALL_RECORD, financeCategoryId, Common_util.ALL_RECORD_NEW);
			if (list != null) {
				for (ExpenseHqItem expenseHqItem : list) {
					FinanceBillFlowDetailsVO vo = new FinanceBillFlowDetailsVO(expenseHqItem);
					fDetailsVOs.add(vo);
				}
			}
		}
		
		Collections.sort(fDetailsVOs,new FinanceBillFlowDetailsVO());				
			for (int i = 0; i < fDetailsVOs.size(); i++) {
				if (i == 0) {
					// 第一条数据为初始金额 防覆盖
					continue;
				}else {
					//1.客户
					if (fDetailsVOs.get(i).getFlowType().equals(FinanceCategory.ACCOUNT_TYPE_NAME_CUST)) {
						if ((fDetailsVOs.get(i).getType() == FinanceBill.FINANCE_INCOME_HQ || fDetailsVOs.get(i).getType() == FinanceBill.FINANCE_INCREASE_HQ || fDetailsVOs.get(i).getType() == FinanceBill.FINANCE_PREINCOME_HQ) && i>0 ) {
							fDetailsVOs.get(i).setBalance(sum+fDetailsVOs.get(i).getTotal());
							//添加借方金额
							fDetailsVOs.get(i).setBorrowerAmount(fDetailsVOs.get(i).getTotal());
							sum = sum + fDetailsVOs.get(i).getTotal();
						}else {														
							fDetailsVOs.get(i).setBalance(sum-fDetailsVOs.get(i).getTotal());
							//添加贷方金额
							fDetailsVOs.get(i).setLenderAmount(fDetailsVOs.get(i).getTotal());
							sum -=fDetailsVOs.get(i).getTotal();
						}
						
					//2.供应商	
					}else if (fDetailsVOs.get(i).getFlowType().equals(FinanceCategory.ACCOUNT_TYPE_NAME_SUPPLIER)) {
						if ((fDetailsVOs.get(i).getType() == FinanceBillSupplier.FINANCE_INCOME_HQ || fDetailsVOs.get(i).getType() == FinanceBillSupplier.FINANCE_INCREASE_HQ) && i>0) {
							fDetailsVOs.get(i).setBalance(sum+fDetailsVOs.get(i).getTotal());
							//添加借方金额
							fDetailsVOs.get(i).setBorrowerAmount(fDetailsVOs.get(i).getTotal());
							sum = sum + fDetailsVOs.get(i).getTotal();
						}else {														
							fDetailsVOs.get(i).setBalance(sum-fDetailsVOs.get(i).getTotal());
							//添加贷方金额
							fDetailsVOs.get(i).setLenderAmount(fDetailsVOs.get(i).getTotal());
							sum -=fDetailsVOs.get(i).getTotal();
						}
					////3.总部费用	
					}else if(fDetailsVOs.get(i).getFlowType().equals(FinanceCategory.ACCOUNT_TYPE_NAME_HQ)) {						
						if ((fDetailsVOs.get(i).getType() == FinanceBill.FINANCE_PAID_HQ) && i>0) {//总部费用
							fDetailsVOs.get(i).setBalance(sum-fDetailsVOs.get(i).getTotal());
							//添加贷方金额
							fDetailsVOs.get(i).setLenderAmount(fDetailsVOs.get(i).getTotal());
							sum -=fDetailsVOs.get(i).getTotal();
						}else {//收益单
							fDetailsVOs.get(i).setBalance(sum+fDetailsVOs.get(i).getTotal());
							//添加借方金额
							fDetailsVOs.get(i).setBorrowerAmount(fDetailsVOs.get(i).getTotal());
							sum = sum + fDetailsVOs.get(i).getTotal();
						}
					//4.机构转账	
					}else {						
						if ((fDetailsVOs.get(i).getType() == FinanceBill.FINANCE_PAID_HQ) && i>0) {
							fDetailsVOs.get(i).setBalance(sum-fDetailsVOs.get(i).getTotal());
							//添加贷方金额
							fDetailsVOs.get(i).setLenderAmount(fDetailsVOs.get(i).getTotal());
							sum -=fDetailsVOs.get(i).getTotal();
						}else {
							fDetailsVOs.get(i).setBalance(sum+fDetailsVOs.get(i).getTotal());
							//添加借方金额
							fDetailsVOs.get(i).setBorrowerAmount(fDetailsVOs.get(i).getTotal());
							sum = sum + fDetailsVOs.get(i).getTotal();
						}
					}

				}
			}
		//补充：添加日小计行信息后的VO	
		List<FinanceBillFlowDetailsVO> vos  = new ArrayList<FinanceBillFlowDetailsVO>();	
		//日小计： 借方金额 ，贷方金额
		double borrow = 0;
		double loan = 0;
		for (int j = 0; j < fDetailsVOs.size(); j++) {
			if (fDetailsVOs.size() == 1) {
				vos.add(fDetailsVOs.get(j));
			} else {
				//注意：这里要跳过第一条数据，这里的第一条数据为单据日期开始时间前的账目余额信息，不计入日合计信息
				if (j == 0) {
					vos.add(fDetailsVOs.get(j));
				} else {
					FinanceBillFlowDetailsVO before = fDetailsVOs.get(j);
					borrow += before.getBorrowerAmount();
					loan += before.getLenderAmount();
					if (j == fDetailsVOs.size() - 1) {
						vos.add(fDetailsVOs.get(j));
						vos.add(new FinanceBillFlowDetailsVO(borrow,loan));
					} else {
						FinanceBillFlowDetailsVO end = fDetailsVOs.get(j + 1);
						if (!before.getBillDateS().equals(end.getBillDateS())) {
							vos.add(fDetailsVOs.get(j));
							vos.add(new FinanceBillFlowDetailsVO(borrow,loan));
							borrow = 0;
							loan = 0;
						} else {
							FinanceBillFlowDetailsVO vo = fDetailsVOs.get(j);
							vos.add(vo);
						}
					}
				}
			}
		}	
		
		data.put("rows", vos);
		data.put("total",fDetailsVOs.size());
		return data;
	}
	

	
	

	public void insertCategory(FinanceActionFormBean formBean, int cardId) {
		FinanceCategory fCategory = financeCategoryImpl.get(cardId, true);
		formBean.setFc(fCategory);
	}

	/**
	 * 
	 * @param id
	 * @param searchStartTime
	 * @param searchEndTime
	 * @return
	 */
	@Transactional
	public Response generateFinanceReport(FinanceActionFormBean formBean,Date startDate, Date endDate) {
		Response response = new Response();
	    
	    List<CustFinanceSummaryItem> list = financeBillImpl.selectFinanceReport(formBean,startDate,endDate);
		Map data = new HashMap<String, List>();
		data.put("rows", list);

		response.setReturnValue(data);
		response.setReturnCode(Response.SUCCESS);
		
		return response;
	}


	private Set<Integer> getFinanceBillCustIDs(int chainId, int type, Date startDate, Date endDate) {
		HashSet<Integer> set = new HashSet<Integer>();
		 //1. 查询数据
	    DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
	    criteria.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));
	
		if (chainId != Common_util.ALL_RECORD_NEW) {
		   criteria.add(Restrictions.eq("cust.id", chainId));
		}
		Date startDate1 = Common_util.formStartDate(new Date(startDate.getTime()));
		Date endDate1 = Common_util.formEndDate(new Date(endDate.getTime()));
		criteria.add(Restrictions.eq("type", type));
		criteria.add(Restrictions.between("billDate", startDate1, endDate1));
		
		List<FinanceBill> billChains = financeBillImpl.getByCritera(criteria, true);
		for (FinanceBill financeBill : billChains) {
			set.add(financeBill.getId());
		}
		return set;
	}
	
	/**
	 * 
	 * @param fCategoryId
	 * @param set
	 * @return
	 */
	private String getTotal(int fCategoryId,Set<Integer> set) {
		if (set.size()>0) {
			//HibernateTemplate hibernateTemplate = new HibernateTemplate();
			DetachedCriteria fbCriteria = DetachedCriteria.forClass(FinanceBillItem.class);
			fbCriteria.setProjection(Projections.sum("total"));
			fbCriteria.add(Restrictions.eq("financeCategory.id", fCategoryId));
			fbCriteria.add(Restrictions.in("financeBill.id", set));
		
			List<Object> amt =  financeBillImpl.getByCriteriaProjection(fbCriteria, true);
			return String.valueOf(amt.get(0));
		}else {
			return "0";
		}
	}

	/**
	 * 查询机构转账记录
	 * @param formBean
	 * @return
	 */
	public Response searchFinanceBillCorpFlow(FinanceActionFormBean formBean, Integer page, Integer rowPerPage, String sortName, String sortOrder) {
		Response response  = new Response();
		
		DetachedCriteria criteria = buildFinanceBillCorpFlowCriteria(formBean);
		criteria.setProjection(Projections.rowCount());
		int total = Common_util.getProjectionSingleValue(financeBillCoreFlowImpl.getByCriteriaProjection(criteria, true));
		
		
		DetachedCriteria criteria2 = buildFinanceBillCorpFlowCriteria(formBean);
		if (sortName.equals("statusS"))
			sortName = "status";
		if (sortOrder.equals("asc"))
			criteria2.addOrder(Order.asc(sortName));
		else 
			criteria2.addOrder(Order.desc(sortName));
		
		List<FinanceBillCorpFlow> financeBillCorpFlows = financeBillCoreFlowImpl.getByCritera(criteria2, Common_util.getFirstRecord(page, rowPerPage), rowPerPage, true);
		

		List<FinanceBillCorpFlowVO> flowVOs = new ArrayList<FinanceBillCorpFlowVO>();
		for (FinanceBillCorpFlow financeBillCorpFlow : financeBillCorpFlows) {
			flowVOs.add(new FinanceBillCorpFlowVO(financeBillCorpFlow));
		}
		
		Map data = new HashMap<String, List>();
		data.put("rows", flowVOs);
		data.put("total", total);
		
		response.setReturnValue(data);
		response.setReturnCode(Response.SUCCESS);
		
		
		return response;
	}

	/**
	 * 构造查询条件的criteria
	 * @param formBean
	 * @return
	 */
	private DetachedCriteria buildFinanceBillCorpFlowCriteria(FinanceActionFormBean formBean) {
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBillCorpFlow.class);	
		FinanceBillCorpFlow financeBillCorpFlow = formBean.getFinanceBillCorpFlow();
		
		if (financeBillCorpFlow.getStatus() != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("status", formBean.getFinanceBillCorpFlow().getStatus()));
		} else 
			criteria.add(Restrictions.ne("status",FinanceBillCorpFlow.STATUS_DELETED ));
		 		
		if (financeBillCorpFlow.getFromAcctId().getId() != Common_util.ALL_RECORD) {
			int acctId = financeBillCorpFlow.getFromAcctId().getId();
			criteria.add(Restrictions.or(Restrictions.eq("fromAcctId.id", acctId), Restrictions.eq("toAcctId.id", acctId)));
		}
		if (financeBillCorpFlow.getUserId().getUser_id() !=Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("userId.user_id", formBean.getFinanceBillCorpFlow().getUserId().getUser_id()));
		}
		criteria.add(Restrictions.between("date", formBean.getSearchStartTime(), formBean.getSearchEndTime()));
		return criteria;
	}
	
	
	/**
	 * 构造查询条件的criteria
	 * @param formBean
	 * @return
	 */
	private DetachedCriteria buildExpenseHqCriteria(FinanceActionFormBean formBean) {
		DetachedCriteria criteria = DetachedCriteria.forClass(ExpenseHq.class);	
		ExpenseHq expenseHq = formBean.getExpenseHq();
		if (expenseHq.getId() != Common_util.ALL_RECORD_NEW) {
			criteria.add(Restrictions.eq("id", expenseHq.getId()));
			return criteria;
		}
		if (expenseHq.getType() != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("type", expenseHq.getType()));
		}
		
		if (expenseHq.getStatus() != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("status", formBean.getExpenseHq().getStatus()));
		} else 
			criteria.add(Restrictions.ne("status",ExpenseHq.STATUS_DELETED ));
		 		

		if (expenseHq.getFinanceCategory().getId() != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("financeCategory.id",expenseHq.getFinanceCategory().getId() ));
		}
		
		criteria.add(Restrictions.between("expenseDate", formBean.getSearchStartTime(), formBean.getSearchEndTime()));
		return criteria;
	}
	

	/**
	 * 查询所有支持转账的账户机构信息
	 * @return
	 */
	public List<FinanceCategory> selectIsTransferAccountsFc() {		
		return financeCategoryImpl.selectIsTransferAccountsFc();
	}
	
	/**
	 * 查询所有账户机构信息
	 * @return
	 */
	public List<FinanceCategory> selectFinanceCategorys() {		
		return financeCategoryImpl.getAllNormal(true);
	}
	
	/**
	 * 保存finance bill corp flow 草稿
	 * @return
	 */
	@Transactional
	public Response saveDraftFbillCorpFlow(FinanceBillCorpFlow financeBillCorpFlow,UserInfor userInfor){
		Response response = new Response();
		validateFBCorpFlow(financeBillCorpFlow,response);

		if(response.isSuccess()) {	
			financeBillCorpFlow.setStatus(FinanceBillCorpFlow.STATUS_DRAFT);
			if (financeBillCorpFlow.getId() == 0 ) {
				addFinanceCorpFlowInfor(financeBillCorpFlow, userInfor);
				financeBillCoreFlowImpl.save(financeBillCorpFlow, true);
				response.setSuccess("转账单据创建成功");				
			} else {
				FinanceBillCorpFlow flow = financeBillCoreFlowImpl.get(financeBillCorpFlow.getId(), true);
				if (flow.getStatus() == FinanceBillCorpFlow.STATUS_DRAFT) {
					financeBillCoreFlowImpl.copyInfor(flow,financeBillCorpFlow);
					financeBillCoreFlowImpl.update(flow, true);
					response.setSuccess("转账单据修改成功");	
				} else  {
					response.setFail("此单据状态,无法再次修改 : " + flow.getStatus());
				}
			}			
		}
		
		return response;
	}
	
	/**
	 * 过账finance bill corp flow
	 * @param financeBillCorpFlow
	 * @param userInfor
	 * @return
	 * @throws Exception 
	 */
	@Transactional
	public Response postFBillCorpFlow (FinanceBillCorpFlow financeBillCorpFlow,UserInfor userInfor) throws Exception{
		Response response = new Response();
		validateFBCorpFlow(financeBillCorpFlow,response);

		if(response.isSuccess()) {	
			financeBillCorpFlow.setStatus(FinanceBillCorpFlow.STATUS_COMPLETE);
			if (financeBillCorpFlow.getId() == 0 ) {
				addFinanceCorpFlowInfor(financeBillCorpFlow, userInfor);	
				//1. 保存financeBillCorpFlow
				financeBillCoreFlowImpl.save(financeBillCorpFlow, true);

				
				//2. 保存流水
				addFinanceCategoryFlow(financeBillCorpFlow, false);
			} else {
				FinanceBillCorpFlow flow = financeBillCoreFlowImpl.get(financeBillCorpFlow.getId(), true);
				if (flow.getStatus() == FinanceBillCorpFlow.STATUS_DRAFT) {
					financeBillCoreFlowImpl.copyInfor(flow,financeBillCorpFlow);
					//1. 保存financeBillCorpFlow
					financeBillCoreFlowImpl.update(flow, true);
					
					//2. 保存流水
					addFinanceCategoryFlow(flow, false);
				} else  {
					response.setFail("此单据状态,无法再次修改 : " + flow.getStatus());
					return response;
				}
			}

			response.setSuccess("转账创建成功");	
						
		}
		
		return response;
	}
	
	/**
	 * 删除机构转账记录
	 * @param financeBillCorpFlow
	 * @return
	 */
	@Transactional
	public Response deleteFbillCoreFlow(FinanceBillCorpFlow financeBillCorpFlow,UserInfor userInfor) {
		Response response = new Response();
		
		if (financeBillCorpFlow.getId() != 0) {
			FinanceBillCorpFlow flow = financeBillCoreFlowImpl.get(financeBillCorpFlow.getId(), true);
			if (flow.getStatus() == FinanceBillCorpFlow.STATUS_DRAFT) {	
				flow.setLastUpdateDate(new Date());
				flow.setStatus(FinanceBillCorpFlow.STATUS_DELETED);
				financeBillCoreFlowImpl.update(flow,true);
				response.setSuccess("删除成功!");
			} else  {
				response.setFail("此单据状态,无法删除 : " + flow.getStatus());
			}
		} else 
			response.setFail("单据尚未保存,无需删除");

		return response;
	}

	/**
	 * 红冲finance bill corp flow 单据
	 * @param financeBillCorpFlow
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response cancelFbillCorpFlow(FinanceBillCorpFlow financeBillCorpFlow, UserInfor loginUserInfor) {
		Response response = new Response();	
		int corpFlowId = financeBillCorpFlow.getId();
		if (corpFlowId == 0) {
			response.setFail("初始单据无法红冲");
		} else {
			FinanceBillCorpFlow flow = financeBillCoreFlowImpl.get(financeBillCorpFlow.getId(), true);
			if (flow.getStatus() != FinanceBillCorpFlow.STATUS_COMPLETE) {
				response.setFail("此单据状态,无法红冲 : " + flow.getStatus());
			} else  {
				//红冲单据
				flow.setStatus(FinanceBillCorpFlow.STATUS_CANCEL);
				
				//1. 保存当前红冲单据
				addFinanceCorpFlowInfor(flow, loginUserInfor);
				financeBillCoreFlowImpl.save(flow, true);
				
				//2.保存红冲流水
				addFinanceCategoryFlow(flow, true);
				response.setSuccess("红冲单据成功");	
			}
		}

		return response;
	}

	
	
	/**
	 * 添加机构流水/红冲
	 * @param financeBillCorpFlow
	 * @param isHc (isCancel)
	 */
	private void addFinanceCategoryFlow(FinanceBillCorpFlow financeBillCorpFlow,Boolean isHc) {
		FinanceCategoryFlow fromflow = new FinanceCategoryFlow();
		FinanceCategoryFlow toFlow = new FinanceCategoryFlow();
		
		Date orderDate = financeBillCorpFlow.getDate();
		fromflow.setDate(orderDate);
		toFlow.setDate(orderDate);
		
		int fromFlowFlag = -1;
		int toFlowFlag = 1;
		String comment = "B:B:" +financeBillCorpFlow.getId();
		if (isHc) {
			fromFlowFlag *= -1;
			toFlowFlag *= -1;
			comment += ":true";
		} else 
			comment += ":false";
		
		//1. 计算from acct
		fromflow.setFinanceCategoryId(financeBillCorpFlow.getFromAcctId().getId());
		fromflow.setAmt(financeBillCorpFlow.getAmount() * fromFlowFlag);	
		fromflow.setComment(comment);
		
		financeCategoryFlowDaoImpl.save(fromflow, true);
		
		//2. 计算to acct
		toFlow.setFinanceCategoryId(financeBillCorpFlow.getToAcctId().getId());
		toFlow.setAmt(financeBillCorpFlow.getAmount() * toFlowFlag);	
		toFlow.setComment(comment);
		financeCategoryFlowDaoImpl.save(toFlow, true);
	}
	
	/**
	 * 添加总部费用流水/红冲
	 * @param financeBillCorpFlow
	 * @param isHc (isCancel)
	 */
	private void addHqExpenseFcFlow(ExpenseHq expenseHq,Boolean isHc) {
		FinanceCategoryFlow fromflow = new FinanceCategoryFlow();
		FinanceCategoryFlow toFlow = new FinanceCategoryFlow();
		
		Date orderDate = expenseHq.getExpenseDate();
		fromflow.setDate(orderDate);
		toFlow.setDate(orderDate);

		int isCancel = -1;
		String comment = "";
		if (expenseHq.getType() == ExpenseHq.DOCUMENT_TYPE_HQ_COST) {//总部费用单据
			comment = "B:C:" +expenseHq.getId();
		}else if (expenseHq.getType() == ExpenseHq.DOCUMENT_TYPE_HQ_INCOME) {//总部收益单据
			comment = "B:D:" +expenseHq.getId();
		}
		
		if (isHc) {
			isCancel *= -1;
			comment += ":true";
		} else 
			comment += ":false";
		
		//添加支出流水信息
		fromflow.setFinanceCategoryId(expenseHq.getFinanceCategory().getId());
		if (expenseHq.getType() == ExpenseHq.DOCUMENT_TYPE_HQ_COST) {//总部费用单据		
			fromflow.setAmt(expenseHq.getAmount() * isCancel);
		}else if (expenseHq.getType() == ExpenseHq.DOCUMENT_TYPE_HQ_INCOME) {//总部收益单据
			isCancel*= -1;
			fromflow.setAmt(expenseHq.getAmount() * isCancel);
		}
			
		fromflow.setComment(comment);
		financeCategoryFlowDaoImpl.save(fromflow, true);
	}
	
	
	/**
	 * 生成机构转账记录
	 * @param financeBillCorpFlow
	 * @param userInfor
	 * @return
	 */
	private void addFinanceCorpFlowInfor(FinanceBillCorpFlow financeBillCorpFlow,UserInfor userInfor) {
		financeBillCorpFlow.setUserId(userInfor);	
		if (financeBillCorpFlow.getCreateDate() == null)
		    financeBillCorpFlow.setCreateDate(new Date());
		financeBillCorpFlow.setLastUpdateDate(new Date());
	}
	
	/**
	 * 创建总部费用信息
	 * @param financeBillCorpFlow
	 * @param userInfor
	 * @return
	 */
	private void addExpenseInfor(ExpenseHq expenseHq,UserInfor userInfor) {
		expenseHq.setUser(userInfor);	
		if (expenseHq.getCreateDate() == null) 
			expenseHq.setCreateDate(new Date());
		
		expenseHq.setLastUpdateDate(new Date());
	}

	
	/**
	 * 校验机构转账表单信息
	 * @param financeBillCorpFlow
	 * @return
	 */
	private void validateFBCorpFlow(FinanceBillCorpFlow financeBillCorpFlow, Response response) {
		
		double fromSumAmount = financeCategoryFlowImpl.getAccumulateAcctFlow(financeBillCorpFlow.getFromAcctId().getId()) ;
		//1.账户余额 = 账目流水 +账目期初
		FinanceCategory category = financeCategoryImpl.get(financeBillCorpFlow.getFromAcctId().getId(), true);
		if (category != null && category.getIsTransferAccounts() == FinanceCategory.SUPPORT_TRANSFER_ACCOUNTS) {
			fromSumAmount += category.getInitialAmt();
		}		
		//2.判断金额是否是非法数值(注：当double数值过大时候，数值会出现E,这是因为使用了科学技术法的原因）
		String amount = Common_util.doubleTransitionString(financeBillCorpFlow.getAmount(), 4);
		if (StrCheckUtils.isContainLetter(amount) || StrCheckUtils.isContainSpecialCharacterTransfer(amount)) {
			response.setFail("转帐金额为非法数值,请重新输入");
		}else if (financeBillCorpFlow.getAmount() <= 0) {
			response.setFail("转帐金额必须大于0,请重新输入");				
		}
		
// DATE: 2025.6.24
// DESCRIBE: 允许转出账户余额小于此次转账金额			
//		else if (financeBillCorpFlow.getAmount() > fromSumAmount) {
//			response.setFail("当前转出账户剩余金额小于此次转出金额,无法转出 : " + fromSumAmount);
//		}

	}
	
	
	/**
	 * 校验总部费用表单信息
	 * @param financeBillCorpFlow
	 * @return
	 */
	private boolean validateExpenseHq(ExpenseHq expenseHq, Response response) {	
		boolean isCheck = true;
		if (expenseHq.getList().size() == 0) {
			response.setFail("费用类型明细为空,请添加费用类型后重新提交！");
			isCheck = false;
		}else if (expenseHq.getFinanceCategory() == null) {
			response.setFail("支出账目为空，请选择支持账目后再提交单据");		
			isCheck = false;
		}
		return isCheck;
	}
	
	/**
	 * 创建总部费用明细
	 * @param expenseHq
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response saveDraftExpense(ExpenseHq expenseHq, UserInfor loginUserInfor) {
		Response response = new Response();

		boolean isCheck =  validateExpenseHq(expenseHq,response);

		if (isCheck) {
			expenseHq.setStatus(ExpenseHq.STATUS_DRAFT);
			if (expenseHq.getId() != 0) {
					ExpenseHq expenseHqInDB = expenseHqImpl.get(expenseHq.getId(), true);
					
					if (expenseHqInDB.getStatus() != ExpenseHq.STATUS_DRAFT) {
						response.setFail("当前费用状态 (" + expenseHqInDB.getStatusS() + "),无法修改");
						return response;
					} else {			

						double amount = groupExpenseHQ(expenseHq);
						expenseHq.setAmount(amount);
						expenseHqImpl.evict(expenseHqInDB);
						expenseHqItemImpl.deleteByExpenseHqId(expenseHq.getId());
						
						addExpenseInfor(expenseHq, loginUserInfor);	
						expenseHq.putListToSet();
						expenseHqImpl.update(expenseHq, true);
						
						
						response.setSuccess("费用单据修改成功!");
					} 
						
				}else {
					addExpenseInfor(expenseHq, loginUserInfor);	
					
					double amount = groupExpenseHQ(expenseHq);
					expenseHq.setAmount(amount);
					
					expenseHq.putListToSet();
					expenseHqImpl.save(expenseHq, true);	
		
					response.setSuccess("费用草稿创建成功");				
				} 	
		}
							
		
		return response;
	}
	
	/**
	 * 出去空的费用list
	 * @param expenseHqInDB
	 */
	private double groupExpenseHQ(ExpenseHq expenseHqInDB) {
		double amount = 0;
		//1.先求和
		for (int i = 0; i < expenseHqInDB.getList().size(); i++) {
			if (expenseHqInDB.getList().get(i) != null) {
				amount += expenseHqInDB.getList().get(i).getAmount();			
			}
		}
		//2删除空的内容
		for (int i = 0; i < expenseHqInDB.getList().size(); i++) {
			if (expenseHqInDB.getList().get(i) == null) {
				expenseHqInDB.getList().remove(i);				
			}
		}
		return amount;
	}

	
	/**
	 * 创建总部费用明细
	 * 
	 * @param expenseHq
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response postExpense(ExpenseHq expenseHq, UserInfor loginUserInfor) {
		Response response = new Response();

		boolean isCheck = validateExpenseHq(expenseHq, response);

		if (isCheck) {
			expenseHq.setStatus(ExpenseHq.STATUS_COMPLETE);
			if (expenseHq.getId() != 0) {
				ExpenseHq expenseHqInDB = expenseHqImpl.get(expenseHq.getId(), true);
				if (expenseHqInDB.getStatus() != ExpenseHq.STATUS_DRAFT) {
					response.setFail("当前费用状态 (" + expenseHqInDB.getStatusS() + "),无法过账");
					return response;
				} else {
					String ordetType = expenseHq.getTypeHQMap().get(expenseHq.getType());
					if (StringUtils.isNotBlank(ordetType)) {
						double amount = groupExpenseHQ(expenseHq);
						expenseHq.setAmount(amount);
						expenseHqImpl.evict(expenseHqInDB);
						expenseHqItemImpl.deleteByExpenseHqId(expenseHq.getId());

						addExpenseInfor(expenseHq, loginUserInfor);
						expenseHq.putListToSet();
						expenseHqImpl.update(expenseHq, true);
						// 2. 保存流水
						addHqExpenseFcFlow(expenseHq, false);					
						response.setSuccess(ordetType+"保存成功");	
					}else {
						response.setFail("单据保存失败：未知单据类型");
						return response;
					}							
				}
			} else {
				String ordetType = expenseHq.getTypeHQMap().get(expenseHq.getType());
				if (StringUtils.isNotBlank(ordetType)) {
				double amount = groupExpenseHQ(expenseHq);
				expenseHq.setAmount(amount);
				expenseHq.putListToSet();
				addExpenseInfor(expenseHq, loginUserInfor);
				expenseHqImpl.save(expenseHq, true);
				// 2. 保存流水
				addHqExpenseFcFlow(expenseHq, false);
				response.setSuccess(ordetType+"创建成功");	
				}else {
					response.setFail("单据保存失败：未知单据类型");
					return response;
				}
			}
		}

		return response;
	}

	/**
	 * 修改总部费用明细
	 * @param expenseHq
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response deleteExpense(ExpenseHq expenseHq, UserInfor loginUserInfor) {
		Response response = new Response();
		
		if (expenseHq.getId() != 0) {
			ExpenseHq eHq = expenseHqImpl.get(expenseHq.getId(), true);
			if (eHq.getStatus() == ExpenseHq.STATUS_DRAFT) {	
				eHq.setLastUpdateDate(new Date());
				eHq.setStatus(ExpenseHq.STATUS_DELETED);
				expenseHqImpl.update(eHq,true);
				response.setSuccess("删除成功!");
			} else  {
				response.setFail("此单据状态,无法删除 : " + expenseHq.getStatus());
			}
		} else 
			response.setFail("单据尚未保存,无需删除");

		return response;
	}
	
	/**
	 * 复制总部费用明细
	 * @param expenseHq
	 * @param loginUserInfor
	 * @return
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	@Transactional
	public Response copyExpense(ExpenseHq expenseHq, UserInfor loginUserInfor) throws IllegalAccessException, InvocationTargetException {
		Response response = new Response();
		
		if (expenseHq.getId() != 0) {
			ExpenseHq eHq = expenseHqImpl.get(expenseHq.getId(), true);
			if (eHq != null) {
				ExpenseHq hq = new ExpenseHq();
				hq.setComment("复制于单据："+eHq.getId());
				hq.setFinanceCategory(eHq.getFinanceCategory());
				hq.setUser(loginUserInfor);
				hq.setAmount(eHq.getAmount());
				hq.setStatus(ExpenseHq.STATUS_DRAFT);
				hq.setExpenseHqItemSet(null);
				hq.setExpenseDate(eHq.getExpenseDate());
				hq.setCreateDate(new Date());
				hq.setLastUpdateDate(new Date());
				expenseHqImpl.save(hq,true);
				if (eHq.getExpenseHqItemSet().size() != 0) {
					for (ExpenseHqItem item : eHq.getExpenseHqItemSet()) {
						ExpenseHqItem eItem = new ExpenseHqItem();
						eItem.setExpenseHq(hq);
						eItem.setAmount(item.getAmount());
						eItem.setComment(item.getComment());
						eItem.setExpenseHqType(item.getExpenseHqType());
						expenseHqItemImpl.save(eItem, true);
					}
				}
				response.setSuccess("单据【"+expenseHq.getId()+"】复制成功");
			}else {
				response.setFail("复制失败，单据【"+expenseHq.getId()+"】不存在");
			}												
		} else 
			response.setFail("未知单据，复制异常");
		return response;
	}

	
	/**
	 * 红冲总部费用明细
	 * @param expenseHq
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response cancelExpense(ExpenseHq expenseHq, UserInfor loginUserInfor) {
		Response response = new Response();	
		ExpenseHq eHq = expenseHqImpl.get(expenseHq.getId(), true);
		
		if (eHq == null) {
			response.setFail("单据无法红冲 : 单据号" + expenseHq.getId() + "无法在数据库找到");
		}else {
		
			if (eHq.getStatus() != ExpenseHq.STATUS_COMPLETE) {
				if (eHq.getStatus() == BaseOrder.STATUS_DRAFT) {
					response.setFail("草稿状态的单据,无法红冲 ");
				} else if (eHq.getStatus() == BaseOrder.STATUS_CANCEL) {
					response.setFail("此单据已红冲 ,请勿重复红冲");
				} else {
					response.setFail("此单据无法红冲红冲 ,代码 : " + eHq.getStatus());
				}				
			} else  {
				//红冲单据
				eHq.setStatus(FinanceBillCorpFlow.STATUS_CANCEL);	
				eHq.setLastUpdateDate(Common_util.getToday());
				
				//1.红冲当前单据
				expenseHqImpl.save(eHq, true);
				
				//2.保存红冲流水
				addHqExpenseFcFlow(eHq, true);
				
				response.setSuccess("红冲单据成功");	
				
				response.setReturnValue(eHq.getId());
			}
		}

		return response;
	}

	/**
	 * 进入(修改）创建总部费用页面
	 * @param formBean
	 * @param uiBean
	 * @param expenseHq
	 * @return
	 */
	@Transactional
	public Response loadExpense(ExpenseHq expenseHq) {
		Response response = new Response();

    	if (expenseHq.getId() != Common_util.ALL_RECORD_NEW) {
    		expenseHq = expenseHqImpl.get(expenseHq.getId(), true);
			if (expenseHq != null){
				expenseHq.putSetToList();
				
				getExpenseParent(expenseHq);
				
				response.setReturnValue(expenseHq);
			} else {
				response.setFail("无法获取账目信息 : " + expenseHq.getId());
				return response;
			}
		} else 
			response.setReturnValue(expenseHq);

    	return response;
	}

	
	private void getExpenseParent(ExpenseHq expenseHq) {
		List<ExpenseHqItem> items = expenseHq.getList();
		for (ExpenseHqItem item : items) {
			ExpenseHqType type = item.getExpenseHqType();
			
			ExpenseHqType parenType = expenseHqTypeImpl.get(type.getParentId(), true);
			if (parenType != null) {
				type.setParentName(parenType.getName());
			}
		}
		
	}

	/**
	 * 查询总部费用支出信息
	 * @param formBean
	 * @param page
	 * @param rows
	 * @param sort
	 * @param order
	 * @return
	 */
	public Response searchExpense(FinanceActionFormBean formBean, int page, int rows, String sort, String order) {
		Response response  = new Response();
		
		DetachedCriteria criteria = buildExpenseHqCriteria(formBean);
		criteria.setProjection(Projections.rowCount());
		int total = Common_util.getProjectionSingleValue(expenseHqImpl.getByCriteriaProjection(criteria, true));
		
		DetachedCriteria criteria2 = buildExpenseHqCriteria(formBean);
		if (order.equals("asc"))
			criteria2.addOrder(Order.asc(sort));
		else 
			criteria2.addOrder(Order.desc(sort));
	
		List<ExpenseHq> expenseHqs = expenseHqImpl.getByCritera(criteria2, Common_util.getFirstRecord(page, rows), rows, true);
		List<ExpenseHqType> levelOne = expenseHqTypeImpl.selectByType(ExpenseHqType.COST_TYPE_HQ);
		Map<Integer, ExpenseHqType> map = new HashMap<Integer, ExpenseHqType>();
		for (ExpenseHqType expenseHqType : levelOne) {
			map.put(expenseHqType.getId(), expenseHqType);
		}
		List<ExpenseHqVO> eVos = new ArrayList<ExpenseHqVO>();
		for (ExpenseHq expenseHq : expenseHqs) {
			eVos.add(new ExpenseHqVO(expenseHq,map));
		}
		
		Map data = new HashMap<String, List>();
		data.put("rows", eVos);
		data.put("total", total);
		
		response.setReturnValue(data);
		response.setReturnCode(Response.SUCCESS);
		
		
		return response;
	}
	
	
	public Response generateAcctFlowHQExcel(String path, FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			Map<String, Object> map = this.getCardFlowDetails(formBean);
			// 查询符合条件的数据
			List<FinanceBillFlowDetailsVO> list = (List<FinanceBillFlowDetailsVO>) map.get("rows");
			FinanceCategory financeCategory = financeCategoryImpl.get(formBean.getFc().getId(), true);
			String accountName = "";
			if (financeCategory == null) {
				response.setFail("当前账目异常，无法下载 : ");
				return response;
			}else {
				accountName = financeCategory.getItemName();
			}
			AccountsFlowTemplate reportTemplate = new AccountsFlowTemplate(formBean.getSearchStartTime(),
					formBean.getSearchEndTime(), accountName, path, list);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}

	public Response selectPrestoreInfo(FinanceActionFormBean formBean, Date startDate,Date endDate) throws ParseException {
		Response response = new Response();
		Map data = new HashMap<String, List>();
	    List<FinancePrestoreInfoVO> list = financeBillImpl.selectPrestoreInfo(formBean,startDate,endDate);
		
		data.put("rows", list);

		response.setReturnValue(data);
		response.setReturnCode(Response.SUCCESS);
		
		return response;
	}


	public void prepareEditExpense(FinanceActionFormBean formBean, FinanceActionUIBean uiBean) {
		//1.正常状态的账号
    	List<FinanceCategory> list = financeCategoryImpl.getHqAccount(true);   	
    	uiBean.setFinanceCategory(list);
    	
    	List<ExpenseHqType> types = new ArrayList<ExpenseHqType>();
       	if (formBean.getExpenseHq().getType() == ExpenseHq.DOCUMENT_TYPE_HQ_COST) {
        	//总部费用类型
        	types = expenseHqTypeImpl.selectExpenseHq();
    
		}else if (formBean.getExpenseHq().getType()  == ExpenseHq.DOCUMENT_TYPE_HQ_INCOME) {
	    	//收益单据费用类型
	    	types = expenseHqTypeImpl.selectExpenseHqIncome();
		}
    	uiBean.setExpenseHqTypes(types);
		
	}
       	
       	
	@SuppressWarnings("unchecked")
	public Response generateFinanceCategoryExcel(String path,FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			List<FinanceCategoryVO> categoryVOs = new ArrayList<FinanceCategoryVO>();
			
			searchFinanceCategory(formBean);
			Map<String, Object> data = (Map<String, Object>) searchFinanceCategory(formBean).getReturnValue();
			List<FinanceCategory> categorys = (List<FinanceCategory>) data.get("rows");
			// 账目流水信息
			Map<Integer, Double> acctFlowMap = financeCategoryFlowImpl.getAccumulateAcctFlowMap();


			if (categorys != null) {
				for (FinanceCategory category : categorys) {					
					//千禧预收款账目
					if (category.getType() == FinanceCategory.PREPAY_ACCT_TYPE && category.getBelongTo2() == FinanceCategory.BELONG_TO_QX) {	
						List<Integer> qxCustIds = headQEntityTagDaoImpl.selectIdsByTagId(HeadQTag.HEADQ_QX_CUST_TAG_ID);
						//获取客户预存金sum = 所有客户期初预存金合计 + chainFinanceTrace预存金合计(预存金清账日期2025.3.1后合计金额）				
						Double advancePay = headQCustDaoImpl.selectPbAmount(HeadQTag.HEADQ_QX_CUST_TAG_ID) + chainFinanceTraceImpl.getSumAdvancePay(SystemParm.getPrepayFlowDateS(),qxCustIds);
						FinanceCategoryVO vo = new FinanceCategoryVO(category, 0d,advancePay);
						categoryVOs.add(vo);
					}else if (category.getType() == FinanceCategory.PREPAY_ACCT_TYPE && category.getBelongTo2() == FinanceCategory.BELONG_TO_XLC) {	
						//禧乐仓预收款账目
						List<Integer> xlcCustIds = headQEntityTagDaoImpl.selectIdsByTagId(HeadQTag.HEADQ_XLC_CUST_TAG_ID);				
						Double advancePay = headQCustDaoImpl.selectPbAmount(HeadQTag.HEADQ_XLC_CUST_TAG_ID) + chainFinanceTraceImpl.getSumAdvancePay(null,xlcCustIds);
						FinanceCategoryVO vo = new FinanceCategoryVO(category, 0d,advancePay);
						categoryVOs.add(vo);
					}else {
						FinanceCategoryVO vo = new FinanceCategoryVO(category, acctFlowMap.get(category.getId()),0d);
						categoryVOs.add(vo);
					}
				}
			}

			FinanceCategoryTemplate categoryTemplate = new FinanceCategoryTemplate(path, categoryVOs);
			HSSFWorkbook wb = categoryTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}

	public void insertFinanceCategorys(FinanceActionFormBean formBean, FinanceActionUIBean uiBean) {
		uiBean.setFinanceCategory(financeCategoryImpl.getAll(true));
		
	}
	
	
	/**
	 * 下载全部（或选择）账目流水
	 * @param path
	 * @param formBean
	 * @return
	 */
	public Response generateFcAllFlowExcel(String path, FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			List<FinanceBillFlowDetailsVO> list = new ArrayList<FinanceBillFlowDetailsVO>();
			formBean.setFinanceCategoryType(Common_util.ALL_RECORD);//账目类型取所有
			if (formBean.getIds().size() !=0) {
				for (Integer financeCategoryId : formBean.getIds()) {
					formBean.getFc().setId(financeCategoryId);
					List<FinanceBillFlowDetailsVO> vos = (List<FinanceBillFlowDetailsVO>) this.getCardFlowDetails(formBean).get("rows");
					list.addAll(vos);
				}
			}
			AllAccountsFlowTemplate reportTemplate = new AllAccountsFlowTemplate(formBean.getSearchStartTime(),
					formBean.getSearchEndTime(),  path, list);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	

	public Response generateFcFlowExcel(String path, FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			List<FinanceBillFlowDetailsVO> list = new ArrayList<FinanceBillFlowDetailsVO>();
			if (formBean.getIds().size() !=0) {
				for (Integer financeCategoryId : formBean.getIds()) {
					formBean.getFc().setId(financeCategoryId);
					formBean.setFinanceCategoryType(Common_util.ALL_RECORD);
					List<FinanceBillFlowDetailsVO> vos = (List<FinanceBillFlowDetailsVO>) this.getCardFlowDetails(formBean).get("rows");
					double amount = 0;
					for (FinanceBillFlowDetailsVO financeBillFlowDetailsVO : vos) {
						amount += financeBillFlowDetailsVO.getTotal();
					}
					vos.get(0).setBillDateS(null);
					vos.get(0).setComment(vos.get(0).getBillDateS()+ ":" +vos.get(0).getFinanceCategoryName());
					vos.get(0).setBorrowerAmount(amount);
					vos.get(0).setBalance(0);
					list.addAll(vos);
				}
			}
						
			List<FinanceBillFlowDetailsVO> vos = new ArrayList<FinanceBillFlowDetailsVO>();
			for (FinanceBillFlowDetailsVO vo : list) {
				insertFinanceBillDetailsVo(vo, vos);
			}
									
			AllAccountsJSFlowTemplate reportTemplate = new AllAccountsJSFlowTemplate(formBean.getSearchStartTime(),
					formBean.getSearchEndTime(),  path, vos);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	
	
	public void insertFinanceBillDetailsVo(FinanceBillFlowDetailsVO vo,List<FinanceBillFlowDetailsVO> vos) throws ParseException {
		if (vo.getFlowId() !=0) {
			//费用
			FinanceBillFlowDetailsVO advance = new FinanceBillFlowDetailsVO();
			advance.setFlowId(vo.getFlowId());
			advance.setFlowName(vo.getFlowName());
			advance.setTransferType(vo.getTransferType());
			advance.setFlowType(vo.getFlowType());
			advance.setFinanceCategoryName(vo.getFlowName());
			advance.setBillDateS(Common_util.dateFormat.parse(vo.getBillDateS()));
			advance.setComment(vo.getComment());
			if (vo.getBorrowerAmount()>0) {
				advance.setLenderAmount(vo.getBorrowerAmount());
				advance.setBorrowerAmount(0);
				
			}
			if (vo.getLenderAmount()>0) {
				advance.setBorrowerAmount(vo.getLenderAmount());
				advance.setLenderAmount(0);
			}
			advance.setBalance(0);
			vos.add(advance);
			//账目
			FinanceBillFlowDetailsVO goOut = new FinanceBillFlowDetailsVO();
			goOut.setFlowId(vo.getFlowId());
			goOut.setFlowName(vo.getFlowName());
			goOut.setTransferType(vo.getTransferType());
			goOut.setFlowType(vo.getFlowType());
			goOut.setFinanceCategoryName(vo.getFinanceCategoryName() +" : "+vo.getTransferType());
			goOut.setBillDateS(Common_util.dateFormat.parse(vo.getBillDateS()));
			goOut.setComment(vo.getComment());
			goOut.setLenderAmount(vo.getLenderAmount());
			goOut.setBorrowerAmount(vo.getBorrowerAmount());
			goOut.setBalance(vo.getBalance());
			vos.add(goOut);
		}else {
			vos.add(vo);
		}

	}

	public FinanceBillPrintVO selectFinanceBillById(int id) {
		FinanceBill bill = financeBillImpl.get(id, true);
		FinanceBillPrintVO billVO = null;
		if (bill != null) {
			List<FinanceBillItem> items = financeBillItemImpl.selectItemsByBillId(id);
			bill.setFinanceBillItemList(items);			
			billVO = new FinanceBillPrintVO(bill);
		}
		return billVO;
	}

	
	/**
	 * 根据转账记录ID，查询转账记录
	 * @param id
	 * @return
	 */
	public FinanceBillCorpFlowVO selectFBCorpFlowById(int id) {
		FinanceBillCorpFlow flow = financeBillCoreFlowImpl.get(id, true);
		FinanceBillCorpFlowVO vo = new FinanceBillCorpFlowVO();
		if (flow != null) {
			vo = new FinanceBillCorpFlowVO(flow);
		}
		return vo;
	}

	/**
	 * 导出总部费用明细
	 * @param string
	 * @param formBean
	 * @return
	 */
	public Response generateExpenseHqDetailsExcel(String path, FinanceActionFormBean formBean) {
		Response response = new Response();
		try {
			Date startDate = formBean.getSearchStartTime();
			loggerLocal.info(startDate.toString());
			Date endDate = formBean.getSearchEndTime();
			loggerLocal.info(endDate.toString());
			
			
			List<ExpenseHqItem> items = expenseHqItemImpl.selectExpenseHqItems(startDate,endDate,formBean.getExpenseHq().getType(),formBean.getExpenseHq().getFinanceCategory().getId(),formBean.getExpenseHq().getId());

			ExpenseHqItemDetailsTemplate reportTemplate = new ExpenseHqItemDetailsTemplate(path, items);
			HSSFWorkbook wb = reportTemplate.process();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}

	/**
	 * 修改客户财务单据备注
	 * @param financeBill
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response updateFinanceBillComment(FinanceBill financeBill, UserInfor loginUserInfor) {
		Response response = new Response();
		String comment = financeBill.getComment();
		if (financeBill.getId() != 0) {
			financeBill = financeBillImpl.get(financeBill.getId(), true);
			if (StringUtils.isNotBlank(comment)) {
				financeBill.setComment(comment);
				financeBill.setUpdateDate(DateUtils.getNowDate());
				financeBillImpl.update(financeBill, true);
				response.setSuccess("备注修改成功");
			}
		} else 
			response.setFail("未知单据");

		return response;
	}

}

